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 v 5.4.0
- Ability to edit own comments - Ability to edit own comments
- Documentation improvements - Documentation improvements
......
load 'deploy'
load 'deploy/assets'
require 'bundler/capistrano'
load 'config/deploy'
...@@ -23,7 +23,7 @@ gem 'omniauth-github' ...@@ -23,7 +23,7 @@ gem 'omniauth-github'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # 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 # Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 1.0.1', require: 'grack' gem 'gitlab-grack', '~> 1.0.1', require: 'grack'
...@@ -35,7 +35,7 @@ gem 'gitlab_omniauth-ldap', '1.0.3', require: "omniauth-ldap" ...@@ -35,7 +35,7 @@ gem 'gitlab_omniauth-ldap', '1.0.3', require: "omniauth-ldap"
gem "gitlab-pygments.rb", '~> 0.3.2', require: 'pygments.rb' gem "gitlab-pygments.rb", '~> 0.3.2', require: 'pygments.rb'
# Git Wiki # Git Wiki
gem "gitlab-gollum-lib", "~> 1.0.0", require: 'gollum-lib' gem "gitlab-gollum-lib", "~> 1.0.1", require: 'gollum-lib'
# Language detection # Language detection
gem "github-linguist", require: "linguist" gem "github-linguist", require: "linguist"
...@@ -173,7 +173,7 @@ group :development, :test do ...@@ -173,7 +173,7 @@ group :development, :test do
gem 'factory_girl_rails' gem 'factory_girl_rails'
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826) # Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
gem 'minitest' gem 'minitest', '~> 4.7.0'
# Generate Fake data # Generate Fake data
gem "ffaker" gem "ffaker"
...@@ -203,5 +203,5 @@ group :test do ...@@ -203,5 +203,5 @@ group :test do
end end
group :production do group :production do
gem "gitlab_meta", '5.0' gem "gitlab_meta", '6.0'
end 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 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 ...@@ -8,6 +8,22 @@ class Dashboard
@toggleFilter($(event.currentTarget)) @toggleFilter($(event.currentTarget))
@reloadActivities() @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: -> reloadActivities: ->
$(".content_list").html '' $(".content_list").html ''
Pager.init 20, true Pager.init 20, true
......
...@@ -16,20 +16,26 @@ class Dispatcher ...@@ -16,20 +16,26 @@ class Dispatcher
path = page.split(':') path = page.split(':')
switch page switch page
when 'issues:index' when 'projects:issues:index'
Issues.init() Issues.init()
when 'dashboard:show' when 'dashboard:show'
new Dashboard() new Dashboard()
when 'commit:show' when 'projects:commit:show'
new Commit() new Commit()
when 'groups:show', 'teams:show', 'projects:show' when 'groups:show', 'projects:show'
Pager.init(20, true) Pager.init(20, true)
when 'projects:new', 'projects:edit' when 'projects:new', 'projects:edit'
new Project() new Project()
when 'walls:show' when 'projects:walls:show'
new Wall(project_id) new Wall(project_id)
when 'teams:members:index' when 'projects:teams:members:index'
new TeamMembers() new TeamMembers()
when 'groups:people'
new GroupMembers()
when 'projects:tree:show'
new TreeView()
when 'projects:blob:show'
new BlobView()
switch path.first() switch path.first()
when 'admin' then new Admin() when 'admin' then new Admin()
......
class GroupMembers
constructor: ->
$('li.users_group').bind 'ajax:success', ->
$(this).fadeOut()
@GroupMembers = GroupMembers
...@@ -50,11 +50,12 @@ window.startSpinner = -> ...@@ -50,11 +50,12 @@ window.startSpinner = ->
window.stopSpinner = -> window.stopSpinner = ->
$('.turbolink-spinner').fadeOut() $('.turbolink-spinner').fadeOut()
window.stopEndlessScroll = -> window.unbindEvents = ->
$(document).unbind('scroll') $(document).unbind('scroll')
$(document).off('scroll')
document.addEventListener("page:fetch", startSpinner) document.addEventListener("page:fetch", startSpinner)
document.addEventListener("page:fetch", stopEndlessScroll) document.addEventListener("page:fetch", unbindEvents)
document.addEventListener("page:receive", stopSpinner) document.addEventListener("page:receive", stopSpinner)
$ -> $ ->
...@@ -66,7 +67,6 @@ $ -> ...@@ -66,7 +67,6 @@ $ ->
$('.appear-data').fadeIn() $('.appear-data').fadeIn()
e.preventDefault() e.preventDefault()
# Initialize chosen selects # Initialize chosen selects
$('select.chosen').chosen() $('select.chosen').chosen()
...@@ -110,6 +110,10 @@ $ -> ...@@ -110,6 +110,10 @@ $ ->
when 115 when 115
$("#search").focus() $("#search").focus()
e.preventDefault() e.preventDefault()
when 63
new Shortcuts()
e.preventDefault()
# Commit show suppressed diff # Commit show suppressed diff
$(".supp_diff_link").bind "click", -> $(".supp_diff_link").bind "click", ->
......
var NoteList = { var NoteList = {
id: null,
notes_path: null, notes_path: null,
target_params: null, target_params: null,
target_id: 0, target_id: 0,
...@@ -16,6 +16,22 @@ var NoteList = { ...@@ -16,6 +16,22 @@ var NoteList = {
// get initial set of notes // get initial set of notes
NoteList.getContent(); 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 // add a new diff note
$(document).on("click", $(document).on("click",
".js-add-diff-note-button", ".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 ...@@ -12,14 +12,35 @@ class window.ContributorsStatGraph
@master_graph.draw() @master_graph.draw()
add_authors_graph: (author_data) -> add_authors_graph: (author_data) ->
@authors = [] @authors = []
_.each(author_data, (d) => limited_author_data = author_data.slice(0, 100)
_.each(limited_author_data, (d) =>
author_header = @create_author_header(d) author_header = @create_author_header(d)
$(".contributors-list").append(author_header) $(".contributors-list").append(author_header)
@authors[d.author] = author_graph = new ContributorsAuthorGraph(d.dates) @authors[d.author] = author_graph = new ContributorsAuthorGraph(d.dates)
author_graph.draw() author_graph.draw()
) )
format_author_commit_info: (author) -> 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) -> create_author_header: (author) ->
list_item = $('<li/>', { list_item = $('<li/>', {
class: 'person' class: 'person'
...@@ -30,7 +51,7 @@ class window.ContributorsStatGraph ...@@ -30,7 +51,7 @@ class window.ContributorsStatGraph
class: 'commits' class: 'commits'
}) })
author_commit_info = @format_author_commit_info(author) 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_name)
list_item.append(author_commit_info_span) list_item.append(author_commit_info_span)
list_item list_item
...@@ -52,10 +73,10 @@ class window.ContributorsStatGraph ...@@ -52,10 +73,10 @@ class window.ContributorsStatGraph
@field = field @field = field
change_date_header: -> change_date_header: ->
x_domain = ContributorsGraph.prototype.x_domain x_domain = ContributorsGraph.prototype.x_domain
print_date_format = d3.time.format("%B %e %Y"); print_date_format = d3.time.format("%B %e %Y")
print = print_date_format(x_domain[0]) + " - " + print_date_format(x_domain[1]); print = print_date_format(x_domain[0]) + " - " + print_date_format(x_domain[1])
$("#date_header").text(print); $("#date_header").text(print)
redraw_author_commit_info: (author) -> redraw_author_commit_info: (author) ->
author_list_item = $(@authors[author.author].list_item) author_list_item = $(@authors[author.author].list_item)
author_commit_info = @format_author_commit_info(author) author_commit_info = @format_author_commit_info(author)
author_list_item.find("span").text(author_commit_info) author_list_item.find("span").html(author_commit_info)
\ No newline at end of file
...@@ -71,7 +71,7 @@ class window.ContributorsMasterGraph extends ContributorsGraph ...@@ -71,7 +71,7 @@ class window.ContributorsMasterGraph extends ContributorsGraph
super @width, @height super @width, @height
create_axes: -> create_axes: ->
@x_axis = d3.svg.axis().scale(@x).orient("bottom") @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: -> create_svg: ->
@svg = d3.select("#contributors-master").append("svg") @svg = d3.select("#contributors-master").append("svg")
.attr("width", @width + @MARGIN.left + @MARGIN.right) .attr("width", @width + @MARGIN.left + @MARGIN.right)
...@@ -130,8 +130,8 @@ class window.ContributorsAuthorGraph extends ContributorsGraph ...@@ -130,8 +130,8 @@ class window.ContributorsAuthorGraph extends ContributorsGraph
create_scale: -> create_scale: ->
super @width, @height super @width, @height
create_axes: -> create_axes: ->
@x_axis = d3.svg.axis().scale(@x).orient("bottom").tickFormat(d3.time.format("%m/%d")); @x_axis = d3.svg.axis().scale(@x).orient("bottom").ticks(8)
@y_axis = d3.svg.axis().scale(@y).orient("left") @y_axis = d3.svg.axis().scale(@y).orient("left").ticks(5)
create_area: (x, y) -> create_area: (x, y) ->
@area = d3.svg.area().x((d) -> @area = d3.svg.area().x((d) ->
parseDate = d3.time.format("%Y-%m-%d").parse parseDate = d3.time.format("%Y-%m-%d").parse
...@@ -148,7 +148,7 @@ class window.ContributorsAuthorGraph extends ContributorsGraph ...@@ -148,7 +148,7 @@ class window.ContributorsAuthorGraph extends ContributorsGraph
.append("g") .append("g")
.attr("transform", "translate(" + @MARGIN.left + "," + @MARGIN.top + ")") .attr("transform", "translate(" + @MARGIN.left + "," + @MARGIN.top + ")")
draw_path: (data) -> 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: -> draw: ->
@create_scale() @create_scale()
@create_axes() @create_axes()
......
# Code browser tree slider class TreeView
# Make the entire tree-item row clickable, but not if clicking another link (like a commit message) constructor: ->
$(".tree-content-holder .tree-item").live 'click', (e) -> @initKeyNav()
# 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") if (e.target.nodeName != "A")
path = $('.tree-item-file-name a', this).attr('href') path = $('.tree-item-file-name a', this).attr('href')
Turbolinks.visit(path) Turbolinks.visit(path)
$ ->
# Show the "Loading commit data" for only the first element # Show the "Loading commit data" for only the first element
$('span.log_loading:first').removeClass('hide') $('span.log_loading:first').removeClass('hide')
# See if there are lines selected initKeyNav: ->
# "#L12" and "#L34-56" supported li = $("tr.tree-item")
highlightBlobLines = -> liSelected = null
if window.location.hash isnt "" $('body').keydown (e) ->
matches = window.location.hash.match(/\#L(\d+)(\-(\d+))?/) if e.which is 40
first_line = parseInt(matches?[1]) if liSelected
last_line = parseInt(matches?[3]) next = liSelected.next()
if next.length > 0
liSelected.removeClass "selected"
liSelected = next.addClass("selected")
else
liSelected = li.eq(0).addClass("selected")
$(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")
unless isNaN first_line $(liSelected).focus()
last_line = first_line if isNaN(last_line) else if e.which is 13
$("#tree-content-holder .highlight .line").removeClass("hll") path = $('.tree-item.selected .tree-item-file-name a').attr('href')
$("#LC#{line}").addClass("hll") for line in [first_line..last_line] Turbolinks.visit(path)
$("#L#{first_line}").ScrollTo()
# Highlight the correct lines on load @TreeView = TreeView
highlightBlobLines()
# Highlight the correct lines when the hash part of the URL changes
$(window).on 'hashchange', highlightBlobLines
...@@ -206,17 +206,6 @@ p.time { ...@@ -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{ .thin_area{
height: 150px; height: 150px;
} }
...@@ -311,14 +300,17 @@ li.note { ...@@ -311,14 +300,17 @@ li.note {
} }
} }
.error_message { .error-message {
@extend .cred;
border-left: 4px solid #E99;
padding: 10px; padding: 10px;
margin-bottom: 10px; background: #C67;
background: #FEE;
padding-left: 20px; padding-left: 20px;
margin: 0;
color: #FFF;
a {
color: #fff;
text-decoration: underline;
}
&.centered { &.centered {
text-align: center; text-align: center;
} }
......
...@@ -87,3 +87,10 @@ fieldset legend { font-size: 17px; } ...@@ -87,3 +87,10 @@ fieldset legend { font-size: 17px; }
color: #333; color: #333;
text-shadow: 0 1px 1px #FFF; text-shadow: 0 1px 1px #FFF;
} }
pre.well-pre {
border: 1px solid #EEE;
background: #f9f9f9;
border-radius: 0;
color: #555;
}
...@@ -16,6 +16,12 @@ ...@@ -16,6 +16,12 @@
color: #888; color: #888;
} }
&.unstyled {
&:hover {
background: none;
}
}
&.smoke { background-color: #f5f5f5; } &.smoke { background-color: #f5f5f5; }
&:hover { &:hover {
......
...@@ -22,6 +22,13 @@ ...@@ -22,6 +22,13 @@
color: $style_color; color: $style_color;
font-weight: bold; font-weight: bold;
} }
&.nav-stacked-menu {
background: #FAFAFA;
li > a {
padding: 20px;
}
}
} }
} }
......
...@@ -7,28 +7,13 @@ ...@@ -7,28 +7,13 @@
@extend .pull-right; @extend .pull-right;
.ui-box { .ui-box {
margin: 3px; margin: 0px;
box-shadow: none;
> .title { > .title {
padding: 2px 15px; padding: 2px 15px;
} }
.nav-projects-tabs li { padding: 0; } .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 @@ ...@@ -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 @@ ...@@ -41,6 +41,8 @@
} }
} }
.event-body { .event-body {
margin-left: 35px;
.commit p { .commit p {
color: #666; color: #666;
padding-top: 5px; padding-top: 5px;
...@@ -51,7 +53,6 @@ ...@@ -51,7 +53,6 @@
.event-note { .event-note {
color: #555; color: #555;
margin-top: 5px; margin-top: 5px;
margin-left: 40px;
pre { pre {
border: none; border: none;
...@@ -77,10 +78,6 @@ ...@@ -77,10 +78,6 @@
margin-right: 5px; margin-right: 5px;
} }
} }
.avatar {
position: relative;
top: -3px;
}
.event_icon { .event_icon {
position: relative; position: relative;
float: right; float: right;
...@@ -95,11 +92,10 @@ ...@@ -95,11 +92,10 @@
} }
} }
ul { ul {
margin-left: 50px;
margin-bottom: 5px; margin-bottom: 5px;
.avatar { .avatar {
width: 18px; width: 18px;
margin-top: 3px; margin: 2px 4px;
} }
} }
...@@ -118,7 +114,12 @@ ...@@ -118,7 +114,12 @@
} }
&.commits-stat { &.commits-stat {
display: block; display: block;
margin-top: 5px; padding: 3px;
margin-top: 3px;
&:hover {
background: none;
}
} }
} }
} }
......
...@@ -17,3 +17,16 @@ ...@@ -17,3 +17,16 @@
} }
} }
.graphs {
.graph-author-commits-count {
}
.graph-additions {
color: #4a2;
}
.graph-deletions {
color: #d12f19;
}
}
...@@ -120,7 +120,7 @@ header { ...@@ -120,7 +120,7 @@ header {
border-bottom: 1px solid #AAA; border-bottom: 1px solid #AAA;
.nav > li > a { .nav > li > a {
color: #DDD; color: #AAA;
text-shadow: 0 1px 0 #444; text-shadow: 0 1px 0 #444;
&:hover { &:hover {
...@@ -130,6 +130,10 @@ header { ...@@ -130,6 +130,10 @@ header {
} }
} }
.turbolink-spinner {
color: #FFF;
}
.search { .search {
.search-input { .search-input {
background-color: #D2D5DA; background-color: #D2D5DA;
...@@ -156,8 +160,11 @@ header { ...@@ -156,8 +160,11 @@ header {
} }
.project_name { .project_name {
a { a {
color: #DDD;
&:hover {
color: #FFF; color: #FFF;
} }
}
color: #fff; color: #fff;
text-shadow: 0 1px 1px #444; text-shadow: 0 1px 1px #444;
} }
......
/* Login Page */ /* Login Page */
body.login-page{ body.login-page{
background: #EEE; background: #474D57;
.container .content { padding-top: 5%; } .container .content { padding-top: 5%; }
} }
......
.main-nav { .main-nav {
background: #f5f5f5;
margin: 30px 0; margin: 30px 0;
margin-top: 10px; margin-top: 0;
padding-top: 4px;
border-bottom: 1px solid #E1E1E1; border-bottom: 1px solid #E1E1E1;
ul { ul {
margin: auto; margin: auto;
height: 39px; height: 40px;
position: relative;
top: 3px;
overflow: hidden; overflow: hidden;
.count { .count {
font-weight: normal; font-weight: normal;
...@@ -33,10 +33,29 @@ ...@@ -33,10 +33,29 @@
display: table-cell; display: table-cell;
width: 1%; width: 1%;
&.active { &.active {
border-bottom: 3px solid #777;
a { a {
color: $style_color; color: $style_color;
font-weight: bolder; 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 @@ ...@@ -54,11 +73,13 @@
display: block; display: block;
text-align: center; text-align: center;
font-weight: normal; font-weight: normal;
height: 36px; height: 38px;
line-height: 34px; line-height: 34px;
color: #777; color: #777;
text-shadow: 0 1px 1px white; text-shadow: 0 1px 1px white;
padding: 0 10px; padding: 0 10px;
text-decoration: none;
padding-top: 2px;
} }
} }
} }
...@@ -27,15 +27,15 @@ ...@@ -27,15 +27,15 @@
} }
&.modern { &.modern {
background: #567; background: #345;
} }
&.gray { &.gray {
background: #708090; background: #373737;
} }
&.violet { &.violet {
background: #657; background: #547;
} }
} }
} }
......
...@@ -23,6 +23,14 @@ ...@@ -23,6 +23,14 @@
} }
cursor: pointer; cursor: pointer;
} }
&.selected {
td {
background: $hover;
border-top: 1px solid #ADF;
border-bottom: 1px solid #ADF;
}
}
} }
} }
......
...@@ -8,4 +8,8 @@ ...@@ -8,4 +8,8 @@
background: #F9F9F9; background: #F9F9F9;
border-left: 1px solid #DDD; border-left: 1px solid #DDD;
} }
.main-nav {
background: #FFF;
}
} }
...@@ -16,15 +16,15 @@ ...@@ -16,15 +16,15 @@
@extend .header-dark; @extend .header-dark;
&.navbar-gitlab { &.navbar-gitlab {
.navbar-inner { .navbar-inner {
background: #657; background: #547;
.app_logo { .app_logo {
&:hover { &:hover {
background-color: #6A5A7A; background-color: #435;
} }
} }
.separator { .separator {
background: #546; background: #435;
border-left: 1px solid #706080; border-left: 1px solid #658;
} }
} }
} }
......
...@@ -16,15 +16,15 @@ ...@@ -16,15 +16,15 @@
@extend .header-dark; @extend .header-dark;
&.navbar-gitlab { &.navbar-gitlab {
.navbar-inner { .navbar-inner {
background: #708090; background: #373737;
.app_logo { .app_logo {
&:hover { &:hover {
background-color: #6A7A8A; background-color: #272727;
} }
} }
.separator { .separator {
background: #607080; background: #272727;
border-left: 1px solid #8090A0; border-left: 1px solid #474747;
} }
} }
} }
......
...@@ -16,15 +16,15 @@ ...@@ -16,15 +16,15 @@
@extend .header-dark; @extend .header-dark;
&.navbar-gitlab { &.navbar-gitlab {
.navbar-inner { .navbar-inner {
background: #567; background: #345;
.app_logo { .app_logo {
&:hover { &:hover {
background-color: #516171; background-color: #234;
} }
} }
.separator { .separator {
background: #456; background: #234;
border-left: 1px solid #678; border-left: 1px solid #456;
} }
} }
} }
......
...@@ -33,7 +33,7 @@ module Projects ...@@ -33,7 +33,7 @@ module Projects
# Find matching namespace and check if it allowed # Find matching namespace and check if it allowed
# for current user if namespace_id passed. # for current user if namespace_id passed.
if allowed_namespace?(current_user, namespace_id) if allowed_namespace?(current_user, namespace_id)
@project.namespace_id = namespace_id unless namespace_id == Namespace.global_id @project.namespace_id = namespace_id
else else
deny_namespace deny_namespace
return @project return @project
...@@ -48,6 +48,7 @@ module Projects ...@@ -48,6 +48,7 @@ module Projects
# Import project from cloneable resource # Import project from cloneable resource
if @project.valid? && @project.import_url.present? if @project.valid? && @project.import_url.present?
shell = Gitlab::Shell.new shell = Gitlab::Shell.new
if shell.import_repository(@project.path_with_namespace, @project.import_url) if shell.import_repository(@project.path_with_namespace, @project.import_url)
# We should create satellite for imported repo # We should create satellite for imported repo
@project.satellite.create unless @project.satellite.exists? @project.satellite.create unless @project.satellite.exists?
...@@ -59,9 +60,13 @@ module Projects ...@@ -59,9 +60,13 @@ module Projects
end end
if @project.save if @project.save
unless @project.group
@project.users_projects.create(project_access: UsersProject::MASTER, user: current_user) @project.users_projects.create(project_access: UsersProject::MASTER, user: current_user)
end end
@project.discover_default_branch
end
@project @project
rescue => ex rescue => ex
@project.errors.add(:base, "Can't save project. Please try again later") @project.errors.add(:base, "Can't save project. Please try again later")
...@@ -75,12 +80,8 @@ module Projects ...@@ -75,12 +80,8 @@ module Projects
end end
def allowed_namespace?(user, namespace_id) def allowed_namespace?(user, namespace_id)
if namespace_id == Namespace.global_id
return user.admin
else
namespace = Namespace.find_by_id(namespace_id) namespace = Namespace.find_by_id(namespace_id)
current_user.can?(:manage_namespace, namespace) current_user.can?(:manage_namespace, namespace)
end end
end end
end
end end
...@@ -5,12 +5,7 @@ module Projects ...@@ -5,12 +5,7 @@ module Projects
allowed_transfer = can?(current_user, :change_namespace, project) || role == :admin allowed_transfer = can?(current_user, :change_namespace, project) || role == :admin
if allowed_transfer && namespace_id.present? if allowed_transfer && namespace_id.present?
if namespace_id == Namespace.global_id if namespace_id.to_i != project.namespace_id
if project.namespace.present?
# Transfer to global namespace from anyone
project.transfer(nil)
end
elsif namespace_id.to_i != project.namespace_id
# Transfer to someone namespace # Transfer to someone namespace
namespace = Namespace.find(namespace_id) namespace = Namespace.find(namespace_id)
project.transfer(namespace) project.transfer(namespace)
......
...@@ -25,7 +25,7 @@ class Admin::GroupsController < Admin::ApplicationController ...@@ -25,7 +25,7 @@ class Admin::GroupsController < Admin::ApplicationController
if @group.save if @group.save
redirect_to [:admin, @group], notice: 'Group was successfully created.' redirect_to [:admin, @group], notice: 'Group was successfully created.'
else else
render action: "new" render "new"
end end
end end
...@@ -34,42 +34,23 @@ class Admin::GroupsController < Admin::ApplicationController ...@@ -34,42 +34,23 @@ class Admin::GroupsController < Admin::ApplicationController
owner_id =group_params.delete(:owner_id) owner_id =group_params.delete(:owner_id)
if owner_id if owner_id
@group.owner = User.find(owner_id) @group.change_owner(User.find(owner_id))
end end
if @group.update_attributes(group_params) if @group.update_attributes(group_params)
redirect_to [:admin, @group], notice: 'Group was successfully updated.' redirect_to [:admin, @group], notice: 'Group was successfully updated.'
else else
render action: "edit" render "edit"
end end
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 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.' redirect_to [:admin, @group], notice: 'Users were successfully added.'
end end
def destroy def destroy
@group.truncate_teams
@group.destroy @group.destroy
redirect_to admin_groups_path, notice: 'Group was successfully deleted.' 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 ...@@ -9,13 +9,13 @@ class Admin::ProjectsController < Admin::ApplicationController
@projects = @projects.where(public: true) if params[:public_only].present? @projects = @projects.where(public: true) if params[:public_only].present?
@projects = @projects.with_push if params[:with_push].present? @projects = @projects.with_push if params[:with_push].present?
@projects = @projects.abandoned if params[:abandoned].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.search(params[:name]) if params[:name].present?
@projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20) @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20)
end end
def show def show
@repository = @project.repository @repository = @project.repository
@group = @project.group
end end
protected 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 class Admin::UsersController < Admin::ApplicationController
before_filter :admin_user, only: [:show, :edit, :update, :destroy] before_filter :user, only: [:show, :edit, :update, :destroy]
def index def index
@admin_users = User.scoped @users = User.scoped
@admin_users = @admin_users.filter(params[:filter]) @users = @users.filter(params[:filter])
@admin_users = @admin_users.search(params[:name]) if params[:name].present? @users = @users.search(params[:name]) if params[:name].present?
@admin_users = @admin_users.alphabetically.page(params[:page]) @users = @users.alphabetically.page(params[:page])
end end
def show def show
# Projects user can be added to @projects = user.authorized_projects
@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
end 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 def new
@admin_user = User.new.with_defaults @user = User.new.with_defaults
end end
def edit def edit
admin_user user
end end
def block def block
if admin_user.block if user.block
redirect_to :back, alert: "Successfully blocked" redirect_to :back, alert: "Successfully blocked"
else else
redirect_to :back, alert: "Error occured. User was not blocked" redirect_to :back, alert: "Error occured. User was not blocked"
...@@ -45,7 +29,7 @@ class Admin::UsersController < Admin::ApplicationController ...@@ -45,7 +29,7 @@ class Admin::UsersController < Admin::ApplicationController
end end
def unblock def unblock
if admin_user.activate if user.activate
redirect_to :back, alert: "Successfully unblocked" redirect_to :back, alert: "Successfully unblocked"
else else
redirect_to :back, alert: "Error occured. User was not unblocked" redirect_to :back, alert: "Error occured. User was not unblocked"
...@@ -60,17 +44,17 @@ class Admin::UsersController < Admin::ApplicationController ...@@ -60,17 +44,17 @@ class Admin::UsersController < Admin::ApplicationController
password_expires_at: Time.now password_expires_at: Time.now
} }
@admin_user = User.new(params[:user].merge(opts), as: :admin) @user = User.new(params[:user].merge(opts), as: :admin)
@admin_user.admin = (admin && admin.to_i > 0) @user.admin = (admin && admin.to_i > 0)
@admin_user.created_by_id = current_user.id @user.created_by_id = current_user.id
respond_to do |format| respond_to do |format|
if @admin_user.save if @user.save
format.html { redirect_to [:admin, @admin_user], notice: 'User was successfully created.' } format.html { redirect_to [:admin, @user], notice: 'User was successfully created.' }
format.json { render json: @admin_user, status: :created, location: @admin_user } format.json { render json: @user, status: :created, location: @user }
else else
format.html { render action: "new" } format.html { render "new" }
format.json { render json: @admin_user.errors, status: :unprocessable_entity } format.json { render json: @user.errors, status: :unprocessable_entity }
end end
end end
end end
...@@ -83,26 +67,26 @@ class Admin::UsersController < Admin::ApplicationController ...@@ -83,26 +67,26 @@ class Admin::UsersController < Admin::ApplicationController
params[:user].delete(:password_confirmation) params[:user].delete(:password_confirmation)
end end
admin_user.admin = (admin && admin.to_i > 0) user.admin = (admin && admin.to_i > 0)
respond_to do |format| respond_to do |format|
if admin_user.update_attributes(params[:user], as: :admin) if user.update_attributes(params[:user], as: :admin)
format.html { redirect_to [:admin, admin_user], notice: 'User was successfully updated.' } format.html { redirect_to [:admin, user], notice: 'User was successfully updated.' }
format.json { head :ok } format.json { head :ok }
else else
# restore username to keep form action url. # restore username to keep form action url.
admin_user.username = params[:id] user.username = params[:id]
format.html { render action: "edit" } format.html { render "edit" }
format.json { render json: admin_user.errors, status: :unprocessable_entity } format.json { render json: user.errors, status: :unprocessable_entity }
end end
end end
end end
def destroy 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 redirect_to admin_users_path, alert: "User is a project owner and can't be removed." and return
end end
admin_user.destroy user.destroy
respond_to do |format| respond_to do |format|
format.html { redirect_to admin_users_path } format.html { redirect_to admin_users_path }
...@@ -112,7 +96,7 @@ class Admin::UsersController < Admin::ApplicationController ...@@ -112,7 +96,7 @@ class Admin::UsersController < Admin::ApplicationController
protected protected
def admin_user def user
@admin_user ||= User.find_by_username!(params[:id]) @user ||= User.find_by_username!(params[:id])
end end
end end
...@@ -95,14 +95,6 @@ class ApplicationController < ActionController::Base ...@@ -95,14 +95,6 @@ class ApplicationController < ActionController::Base
return access_denied! unless can?(current_user, :create_team, nil) return access_denied! unless can?(current_user, :create_team, nil)
end 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! def access_denied!
render "errors/access_denied", layout: "errors", status: 404 render "errors/access_denied", layout: "errors", status: 404
end end
......
class DashboardController < ApplicationController class DashboardController < ApplicationController
respond_to :html respond_to :html
before_filter :load_projects before_filter :load_projects, except: [:projects]
before_filter :event_filter, only: :show before_filter :event_filter, only: :show
def show def show
@groups = current_user.authorized_groups.sort_by(&:human_name) @groups = current_user.authorized_groups.sort_by(&:human_name)
@has_authorized_projects = @projects.count > 0 @has_authorized_projects = @projects.count > 0
@teams = current_user.authorized_teams
@projects_count = @projects.count @projects_count = @projects.count
@projects = @projects.limit(20) @projects = @projects.limit(20)
...@@ -27,18 +26,21 @@ class DashboardController < ApplicationController ...@@ -27,18 +26,21 @@ class DashboardController < ApplicationController
def projects def projects
@projects = case params[:scope] @projects = case params[:scope]
when 'personal' then when 'personal' then
@projects.personal(current_user) current_user.namespace.projects
when 'joined' then when 'joined' then
@projects.joined(current_user) current_user.authorized_projects.joined(current_user)
when 'owned' then
current_user.owned_projects
else else
@projects current_user.authorized_projects
end 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.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 end
# Get authored or assigned open merge requests # Get authored or assigned open merge requests
......
...@@ -63,19 +63,8 @@ class GroupsController < ApplicationController ...@@ -63,19 +63,8 @@ class GroupsController < ApplicationController
def people def people
@project = group.projects.find(params[:project_id]) if params[:project_id] @project = group.projects.find(params[:project_id]) if params[:project_id]
@users = @project ? @project.users : group.users @members = group.users_groups.order('group_access DESC')
@users.sort_by!(&:name) @users_group = UsersGroup.new
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.'
end end
def edit def edit
...@@ -83,7 +72,7 @@ class GroupsController < ApplicationController ...@@ -83,7 +72,7 @@ class GroupsController < ApplicationController
def update def update
group_params = params[:group].dup group_params = params[:group].dup
owner_id =group_params.delete(:owner_id) owner_id = group_params.delete(:owner_id)
if owner_id if owner_id
@group.owner = User.find(owner_id) @group.owner = User.find(owner_id)
......
...@@ -12,4 +12,7 @@ class HelpController < ApplicationController ...@@ -12,4 +12,7 @@ class HelpController < ApplicationController
not_found! not_found!
end end
end end
def shortcuts
end
end end
class KeysController < ApplicationController class Profiles::KeysController < ApplicationController
layout "profile" layout "profile"
respond_to :js, :html
def index def index
@keys = current_user.keys.all @keys = current_user.keys.order('id DESC').all
end end
def show def show
...@@ -12,15 +11,16 @@ class KeysController < ApplicationController ...@@ -12,15 +11,16 @@ class KeysController < ApplicationController
def new def new
@key = current_user.keys.new @key = current_user.keys.new
respond_with(@key)
end end
def create def create
@key = current_user.keys.new(params[:key]) @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 end
def destroy def destroy
...@@ -28,7 +28,7 @@ class KeysController < ApplicationController ...@@ -28,7 +28,7 @@ class KeysController < ApplicationController
@key.destroy @key.destroy
respond_to do |format| respond_to do |format|
format.html { redirect_to keys_url } format.html { redirect_to profile_keys_url }
format.js { render nothing: true } format.js { render nothing: true }
end end
end end
......
class NotificationsController < ApplicationController class Profiles::NotificationsController < ApplicationController
layout 'profile' layout 'profile'
def show def show
@notification = current_user.notification @notification = current_user.notification
@users_projects = current_user.users_projects @users_projects = current_user.users_projects
@users_groups = current_user.users_groups
end end
def update def update
...@@ -12,6 +13,10 @@ class NotificationsController < ApplicationController ...@@ -12,6 +13,10 @@ class NotificationsController < ApplicationController
@saved = if type == 'global' @saved = if type == 'global'
current_user.notification_level = params[:notification_level] current_user.notification_level = params[:notification_level]
current_user.save 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 else
users_project = current_user.users_projects.find(params[:notification_id]) users_project = current_user.users_projects.find(params[:notification_id])
users_project.notification_level = params[:notification_level] users_project.notification_level = params[:notification_level]
......
class PasswordsController < ApplicationController class Profiles::PasswordsController < ApplicationController
layout 'navless' layout 'navless'
skip_before_filter :check_password_expiration skip_before_filter :check_password_expiration
......
class ProjectResourceController < ApplicationController
before_filter :project
before_filter :repository
end
class Projects::ApplicationController < ApplicationController class Projects::ApplicationController < ApplicationController
before_filter :project before_filter :project
before_filter :repository before_filter :repository
layout 'projects'
end end
# Controller for viewing a file's blame # Controller for viewing a file's blame
class BlameController < ProjectResourceController class Projects::BlameController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize # Authorize
......
# Controller for viewing a file's blame # Controller for viewing a file's blame
class BlobController < ProjectResourceController class Projects::BlobController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize # Authorize
......
# Controller for a specific Commit # Controller for a specific Commit
# #
# Not to be confused with CommitsController, plural. # Not to be confused with CommitsController, plural.
class CommitController < ProjectResourceController class Projects::CommitController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_code_access!
......
require "base64" require "base64"
class CommitsController < ProjectResourceController class Projects::CommitsController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize # Authorize
......
class CompareController < ProjectResourceController class Projects::CompareController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_code_access!
......
class DeployKeysController < ProjectResourceController class Projects::DeployKeysController < Projects::ApplicationController
respond_to :html respond_to :html
# Authorize # Authorize
before_filter :authorize_admin_project! before_filter :authorize_admin_project!
layout "project_settings"
def index def index
@enabled_keys = @project.deploy_keys.all @enabled_keys = @project.deploy_keys.all
@available_keys = available_keys - @enabled_keys @available_keys = available_keys - @enabled_keys
......
# Controller for edit a repository's file # Controller for edit a repository's file
class EditTreeController < ProjectResourceController class Projects::EditTreeController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize # Authorize
......
class GraphsController < ProjectResourceController class Projects::GraphsController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_code_access!
...@@ -8,10 +8,18 @@ class GraphsController < ProjectResourceController ...@@ -8,10 +8,18 @@ class GraphsController < ProjectResourceController
respond_to do |format| respond_to do |format|
format.html format.html
format.js do format.js do
@repo = @project.repository fetch_graph
@stats = Gitlab::Git::GitStats.new(@repo.raw, @repo.root_ref)
@log = @stats.parsed_log.to_json
end end
end end
end end
private
def fetch_graph
@log = @project.repository.graph_log.to_json
@success = true
rescue => ex
@log = []
@success = false
end
end end
class HooksController < ProjectResourceController class Projects::HooksController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_admin_project!, only: [:new, :create, :destroy] before_filter :authorize_admin_project!, only: [:new, :create, :destroy]
respond_to :html respond_to :html
layout "project_settings"
def index def index
@hooks = @project.hooks.all @hooks = @project.hooks.all
@hook = ProjectHook.new @hook = ProjectHook.new
......
class IssuesController < ProjectResourceController class Projects::IssuesController < Projects::ApplicationController
before_filter :module_enabled before_filter :module_enabled
before_filter :issue, only: [:edit, :update, :show] before_filter :issue, only: [:edit, :update, :show]
...@@ -23,7 +23,7 @@ class IssuesController < ProjectResourceController ...@@ -23,7 +23,7 @@ class IssuesController < ProjectResourceController
assignee_id, milestone_id = params[:assignee_id], params[:milestone_id] 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? @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
respond_to do |format| respond_to do |format|
......
class LabelsController < ProjectResourceController class Projects::LabelsController < Projects::ApplicationController
before_filter :module_enabled before_filter :module_enabled
# Allow read any issue # Allow read any issue
......
require 'gitlab/satellite/satellite' require 'gitlab/satellite/satellite'
class MergeRequestsController < ProjectResourceController class Projects::MergeRequestsController < Projects::ApplicationController
before_filter :module_enabled before_filter :module_enabled
before_filter :merge_request, only: [:edit, :update, :show, :commits, :diffs, :automerge, :automerge_check, :ci_status] before_filter :merge_request, only: [:edit, :update, :show, :commits, :diffs, :automerge, :automerge_check, :ci_status]
before_filter :validates_merge_request, only: [:show, :diffs] before_filter :validates_merge_request, only: [:show, :diffs]
...@@ -30,7 +30,6 @@ class MergeRequestsController < ProjectResourceController ...@@ -30,7 +30,6 @@ class MergeRequestsController < ProjectResourceController
end end
def diffs def diffs
@diffs = @merge_request.diffs
@commit = @merge_request.last_commit @commit = @merge_request.last_commit
@comments_allowed = @reply_allowed = true @comments_allowed = @reply_allowed = true
...@@ -54,7 +53,7 @@ class MergeRequestsController < ProjectResourceController ...@@ -54,7 +53,7 @@ class MergeRequestsController < ProjectResourceController
@merge_request.reload_code @merge_request.reload_code
redirect_to [@project, @merge_request], notice: 'Merge request was successfully created.' redirect_to [@project, @merge_request], notice: 'Merge request was successfully created.'
else else
render action: "new" render "new"
end end
end end
...@@ -64,7 +63,7 @@ class MergeRequestsController < ProjectResourceController ...@@ -64,7 +63,7 @@ class MergeRequestsController < ProjectResourceController
@merge_request.mark_as_unchecked @merge_request.mark_as_unchecked
redirect_to [@project, @merge_request], notice: 'Merge request was successfully updated.' redirect_to [@project, @merge_request], notice: 'Merge request was successfully updated.'
else else
render action: "edit" render "edit"
end end
end end
......
class MilestonesController < ProjectResourceController class Projects::MilestonesController < Projects::ApplicationController
before_filter :module_enabled before_filter :module_enabled
before_filter :milestone, only: [:edit, :update, :destroy, :show] before_filter :milestone, only: [:edit, :update, :destroy, :show]
......
class NetworkController < ProjectResourceController class Projects::NetworkController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
include ApplicationHelper include ApplicationHelper
......
class NotesController < ProjectResourceController class Projects::NotesController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_note! before_filter :authorize_read_note!
before_filter :authorize_write_note!, only: [:create] before_filter :authorize_write_note!, only: [:create]
......
class ProtectedBranchesController < ProjectResourceController class Projects::ProtectedBranchesController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
# Controller for viewing a file's raw # Controller for viewing a file's raw
class RawController < ProjectResourceController class Projects::RawController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize # Authorize
......
class RefsController < ProjectResourceController class Projects::RefsController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize # Authorize
......
class RepositoriesController < ProjectResourceController class Projects::RepositoriesController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_code_access!
......
class ServicesController < ProjectResourceController class Projects::ServicesController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_admin_project! before_filter :authorize_admin_project!
before_filter :service, only: [:edit, :update, :test] before_filter :service, only: [:edit, :update, :test]
respond_to :html respond_to :html
layout "project_settings"
def index def index
@project.build_missing_services @project.build_missing_services
@services = @project.services.reload @services = @project.services.reload
......
...@@ -14,7 +14,7 @@ class Projects::SnippetsController < Projects::ApplicationController ...@@ -14,7 +14,7 @@ class Projects::SnippetsController < Projects::ApplicationController
# Allow destroy snippet # Allow destroy snippet
before_filter :authorize_admin_project_snippet!, only: [:destroy] before_filter :authorize_admin_project_snippet!, only: [:destroy]
layout 'project_resource' layout 'projects'
respond_to :html respond_to :html
......
class TeamMembersController < ProjectResourceController class Projects::TeamMembersController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_admin_project!, except: [:index, :show] before_filter :authorize_admin_project!, except: [:index, :show]
def index layout "project_settings"
@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)
@assigned_teams = @project.user_team_project_relationships def index
@group = @project.group
@users_projects = @project.users_projects.order('project_access DESC')
end end
def new 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 # Controller for viewing a repository's file structure
class TreeController < ProjectResourceController class Projects::TreeController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize # Authorize
......
class WallsController < ProjectResourceController class Projects::WallsController < Projects::ApplicationController
before_filter :module_enabled before_filter :module_enabled
respond_to :js, :html respond_to :js, :html
......
class WikisController < ProjectResourceController class Projects::WikisController < Projects::ApplicationController
before_filter :authorize_read_wiki! before_filter :authorize_read_wiki!
before_filter :authorize_write_wiki!, only: [:edit, :create, :history] before_filter :authorize_write_wiki!, only: [:edit, :create, :history]
before_filter :authorize_admin_wiki!, only: :destroy before_filter :authorize_admin_wiki!, only: :destroy
......
class ProjectsController < ProjectResourceController class ProjectsController < Projects::ApplicationController
skip_before_filter :project, only: [:new, :create] skip_before_filter :project, only: [:new, :create]
skip_before_filter :repository, only: [:new, :create] skip_before_filter :repository, only: [:new, :create]
...@@ -15,6 +15,7 @@ class ProjectsController < ProjectResourceController ...@@ -15,6 +15,7 @@ class ProjectsController < ProjectResourceController
end end
def edit def edit
render 'edit', layout: "project_settings"
end end
def create def create
...@@ -26,7 +27,7 @@ class ProjectsController < ProjectResourceController ...@@ -26,7 +27,7 @@ class ProjectsController < ProjectResourceController
if @project.saved? if @project.saved?
redirect_to @project redirect_to @project
else else
render action: "new" render "new"
end end
end end
format.js format.js
...@@ -42,7 +43,7 @@ class ProjectsController < ProjectResourceController ...@@ -42,7 +43,7 @@ class ProjectsController < ProjectResourceController
format.html { redirect_to edit_project_path(@project), notice: 'Project was successfully updated.' } format.html { redirect_to edit_project_path(@project), notice: 'Project was successfully updated.' }
format.js format.js
else else
format.html { render action: "edit" } format.html { render "edit", layout: "project_settings" }
format.js format.js
end end
end end
...@@ -89,7 +90,7 @@ class ProjectsController < ProjectResourceController ...@@ -89,7 +90,7 @@ class ProjectsController < ProjectResourceController
redirect_to(@forked_project, notice: 'Project was successfully forked.') redirect_to(@forked_project, notice: 'Project was successfully forked.')
else else
@title = 'Fork project' @title = 'Fork project'
render action: "fork" render "fork"
end end
end end
format.js format.js
...@@ -100,7 +101,7 @@ class ProjectsController < ProjectResourceController ...@@ -100,7 +101,7 @@ class ProjectsController < ProjectResourceController
@suggestions = { @suggestions = {
emojis: Emoji.names, emojis: Emoji.names,
issues: @project.issues.select([:id, :title, :description]), 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| 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 ...@@ -92,11 +92,10 @@ module ApplicationHelper
def search_autocomplete_source def search_autocomplete_source
projects = current_user.authorized_projects.map { |p| { label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) } } 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) } } 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 = [ default_nav = [
{ label: "My Profile", url: profile_path }, { 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: "My Dashboard", url: root_path },
{ label: "Admin Section", url: admin_root_path }, { label: "Admin Section", url: admin_root_path },
] ]
...@@ -116,19 +115,21 @@ module ApplicationHelper ...@@ -116,19 +115,21 @@ module ApplicationHelper
project_nav = [] project_nav = []
if @project && @project.repository.exists? && @project.repository.root_ref if @project && @project.repository.exists? && @project.repository.root_ref
project_nav = [ 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)} - 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)} - 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)} - 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)} - 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)} - 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)} - Wall", url: project_wall_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Wiki", url: project_wikis_path(@project) }, { label: "#{simple_sanitize(@project.name_with_namespace)} - Wiki", url: project_wikis_path(@project) },
] ]
end 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 end
def emoji_autocomplete_source def emoji_autocomplete_source
......
...@@ -109,7 +109,7 @@ module CommitsHelper ...@@ -109,7 +109,7 @@ module CommitsHelper
end end
def commit_to_html commit def commit_to_html commit
escape_javascript(render 'commits/commit', commit: commit) escape_javascript(render 'projects/commits/commit', commit: commit)
end end
def diff_line_content(line) def diff_line_content(line)
......
...@@ -45,13 +45,15 @@ module EventsHelper ...@@ -45,13 +45,15 @@ module EventsHelper
def event_feed_title(event) def event_feed_title(event)
if event.issue? 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? 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? 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? 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 else
"" ""
end end
......
...@@ -14,4 +14,8 @@ module GroupsHelper ...@@ -14,4 +14,8 @@ module GroupsHelper
merge_requests_group_path(@group, options) merge_requests_group_path(@group, options)
end end
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 end
...@@ -3,12 +3,10 @@ module NamespacesHelper ...@@ -3,12 +3,10 @@ module NamespacesHelper
groups = current_user.owned_groups.select {|n| n.type == 'Group'} groups = current_user.owned_groups.select {|n| n.type == 'Group'}
users = current_user.namespaces.reject {|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]} ] 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]} ] users_opts = [ "Users", users.sort_by(&:human_name).map {|u| [u.human_name, u.id]} ]
options = [] options = []
options << global_opts if current_user.admin
options << group_opts options << group_opts
options << users_opts options << users_opts
......
...@@ -10,13 +10,13 @@ module TreeHelper ...@@ -10,13 +10,13 @@ module TreeHelper
tree = "" tree = ""
# Render folders if we have any # 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 # 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 # 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 tree.html_safe
end 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 ...@@ -8,7 +8,7 @@ module Emails
def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id) def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id)
@issue = Issue.find(issue_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 @project = @issue.project
mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.id}", @issue.title)) mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.id}", @issue.title))
end end
......
...@@ -8,7 +8,7 @@ module Emails ...@@ -8,7 +8,7 @@ module Emails
def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id) def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id)
@merge_request = MergeRequest.find(merge_request_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 @project = @merge_request.project
mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.id}", @merge_request.title)) mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.id}", @merge_request.title))
end end
......
...@@ -8,10 +8,10 @@ module Emails ...@@ -8,10 +8,10 @@ module Emails
end end
def project_was_moved_email(user_project_id) def project_was_moved_email(project_id, user_id)
@users_project = UsersProject.find user_project_id @user = User.find user_id
@project = @users_project.project @project = Project.find project_id
mail(to: @users_project.user.email, mail(to: @user.email,
subject: subject("project was moved")) subject: subject("project was moved"))
end end
end end
......
...@@ -10,8 +10,8 @@ class Ability ...@@ -10,8 +10,8 @@ class Ability
when "ProjectSnippet" then project_snippet_abilities(user, subject) when "ProjectSnippet" then project_snippet_abilities(user, subject)
when "PersonalSnippet" then personal_snippet_abilities(user, subject) when "PersonalSnippet" then personal_snippet_abilities(user, subject)
when "MergeRequest" then merge_request_abilities(user, subject) when "MergeRequest" then merge_request_abilities(user, subject)
when "Group", "Namespace" then group_abilities(user, subject) when "Group" then group_abilities(user, subject)
when "UserTeam" then user_team_abilities(user, subject) when "Namespace" then namespace_abilities(user, subject)
else [] else []
end.concat(global_abilities(user)) end.concat(global_abilities(user))
end end
...@@ -19,7 +19,6 @@ class Ability ...@@ -19,7 +19,6 @@ class Ability
def global_abilities(user) def global_abilities(user)
rules = [] rules = []
rules << :create_group if user.can_create_group rules << :create_group if user.can_create_group
rules << :create_team if user.can_create_team
rules rules
end end
...@@ -50,6 +49,10 @@ class Ability ...@@ -50,6 +49,10 @@ class Ability
rules << project_admin_rules rules << project_admin_rules
end end
if project.group && project.group.owners.include?(user)
rules << project_admin_rules
end
rules.flatten rules.flatten
end end
...@@ -132,7 +135,7 @@ class Ability ...@@ -132,7 +135,7 @@ class Ability
rules = [] rules = []
# Only group owner and administrators can manage group # Only group owner and administrators can manage group
if group.owner == user || user.admin? if group.owners.include?(user) || user.admin?
rules << [ rules << [
:manage_group, :manage_group,
:manage_namespace :manage_namespace
...@@ -142,16 +145,14 @@ class Ability ...@@ -142,16 +145,14 @@ class Ability
rules.flatten rules.flatten
end end
def user_team_abilities user, team def namespace_abilities user, namespace
rules = [] rules = []
# Only group owner and administrators can manage team # Only namespace owner and administrators can manage it
if user.admin? || team.owner == user || team.admin?(user) if namespace.owner == user || user.admin?
rules << [ :manage_user_team ] rules << [
end :manage_namespace
]
if team.owner == user || user.admin?
rules << [ :admin_user_team ]
end end
rules.flatten rules.flatten
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
# updated_at :datetime not null # updated_at :datetime not null
# active :boolean default(FALSE), not null # active :boolean default(FALSE), not null
# project_url :string(255) # project_url :string(255)
# subdomain :string(255)
# room :string(255)
# #
class CampfireService < Service 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