Commit a74b66cd authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'master' of dev.gitlab.org:gitlab/gitlabhq into upstream-ce

Signed-off-by: default avatarDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>

Conflicts:
	app/models/group.rb
	app/models/project.rb
	features/steps/shared/project.rb
parents efd08747 a019b49a
......@@ -7,6 +7,19 @@ v 7.1.0
- Add @all mention for comments
- Dont show reply button if user is not signed in
- Expose more information for issues with webhook
- Add a mention of the merge request into the default merge request commit message
- Imrpove code highlight, introduce support for more languages like Go, Clojure, Erlang etc
- Fix concurrency issue in repository download
- Dont allow repository name start with ?
- Improve email threading (Pierre de La Morinerie)
- Cleaner help page
- Group milestones
- Improved email notifications
- Contributors API (sponsored by Mobbr)
- Fix LDAP TLS authentication (Boris HUISGEN)
- Show VERSION information on project sidebar
- Improve branch removal logic when accept MR
- Fix bug where comment form is spawned inside the Reply button
v 7.0.0
- The CPU no longer overheats when you hold down the spacebar
......
......@@ -42,7 +42,7 @@ Please send a merge request with a tested solution or a merge request with a fai
1. **Observed behavior**
1. **Relevant logs and/or screenshots:** Please use code blocks (\`\`\`) to format console output, logs, and code as it's very hard to read otherwise.
1. **Output of checks**
* Results of GitLab [Application Check](doc/install/installation.md#check-application-status) (`sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production`); we will only investigate if the tests are passing
* Results of GitLab [Application Check](doc/install/installation.md#check-application-status) (`sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true`); we will only investigate if the tests are passing
* Version of GitLab you are running; we will only investigate issues in the latest stable and development releases as per the [maintenance policy](MAINTENANCE.md)
* Add the last commit sha1 of the GitLab version you used to replicate the issue (obtainable from the help page)
* Describe your setup (use relevant parts from `sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
......
......@@ -10,8 +10,6 @@ end
gem "rails", "~> 4.1.0"
gem "protected_attributes"
# Make links from text
gem 'rails_autolink', '~> 1.1'
......@@ -23,8 +21,8 @@ gem "mysql2", group: :mysql
gem "pg", group: :postgres
# Auth
gem "devise", '3.0.4'
gem "devise-async", '0.8.0'
gem "devise", '3.2.4'
gem "devise-async", '0.9.0'
gem 'omniauth', "~> 1.1.3"
gem 'omniauth-google-oauth2'
gem 'omniauth-twitter'
......@@ -49,7 +47,6 @@ gem "gitlab-linguist", "~> 3.0.0", require: "linguist"
# API
gem "grape", "~> 0.6.1"
# Replace with rubygems when nesteted entities get released
gem "grape-entity", "~> 0.4.2"
gem 'rack-cors', require: 'rack/cors'
......
......@@ -40,7 +40,7 @@ GEM
axiom-types (0.0.5)
descendants_tracker (~> 0.0.1)
ice_nine (~> 0.9)
bcrypt-ruby (3.1.2)
bcrypt (3.1.7)
better_errors (1.0.1)
coderay (>= 1.0.0)
erubis (>= 2.6.6)
......@@ -94,13 +94,14 @@ GEM
default_value_for (3.0.0)
activerecord (>= 3.2.0, < 5.0)
descendants_tracker (0.0.3)
devise (3.0.4)
bcrypt-ruby (~> 3.0)
devise (3.2.4)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5)
thread_safe (~> 0.1)
warden (~> 1.2.3)
devise-async (0.8.0)
devise (>= 2.2, < 3.2)
devise-async (0.9.0)
devise (~> 3.2)
diff-lcs (1.2.5)
diffy (3.0.3)
docile (1.1.1)
......@@ -175,7 +176,7 @@ GEM
mime-types (~> 1.19)
gitlab_emoji (0.0.1.1)
emoji (~> 1.0.1)
gitlab_git (6.0.0)
gitlab_git (6.0.1)
activesupport (~> 4.0)
charlock_holmes (~> 0.6)
gitlab-grit (~> 2.6)
......@@ -282,7 +283,7 @@ GEM
method_source (0.8.2)
mime-types (1.25.1)
mini_portile (0.6.0)
minitest (5.3.4)
minitest (5.3.5)
multi_json (1.10.1)
multi_xml (0.5.5)
multipart-post (1.2.0)
......@@ -331,8 +332,6 @@ GEM
websocket-driver (>= 0.2.0)
polyglot (0.3.4)
posix-spawn (0.3.8)
protected_attributes (1.0.5)
activemodel (>= 4.0.1, < 5.0)
pry (0.9.12.4)
coderay (~> 1.0)
method_source (~> 0.8)
......@@ -586,8 +585,8 @@ DEPENDENCIES
d3_rails (~> 3.1.4)
database_cleaner
default_value_for (~> 3.0.0)
devise (= 3.0.4)
devise-async (= 0.8.0)
devise (= 3.2.4)
devise-async (= 0.9.0)
diffy (~> 3.0.3)
dropzonejs-rails
email_spec
......@@ -636,7 +635,6 @@ DEPENDENCIES
org-ruby
pg
poltergeist (~> 1.5.1)
protected_attributes
pry
quiet_assets (~> 1.0.1)
rack-attack
......
......@@ -23,7 +23,7 @@
#= require g.raphael-min
#= require g.bar-min
#= require branch-graph
#= require highlightjs.min
#= require highlight.pack
#= require ace/ace
#= require d3
#= require underscore
......
......@@ -376,7 +376,7 @@ class Notes
###
replyToDiscussionNote: (e) =>
form = $(".js-new-note-form")
replyLink = $(e.target)
replyLink = $(e.target).closest(".js-discussion-reply-button")
replyLink.hide()
# insert the form after the button
......
......@@ -152,16 +152,16 @@
}
&.btn-close {
color: #B94A48;
font-weight: bold;
color: $bg_danger;
border-color: $border_danger;
&:hover {
color: #B94A48;
}
}
&.btn-reopen {
color: #468847;
font-weight: bold;
color: $bg_success;
border-color: $border_success;
&:hover {
color: #468847;
}
......
......@@ -177,10 +177,18 @@ li.commit {
.commit-row-description {
font-size: 14px;
border-left: 1px solid #e5e5e5;
padding: 0 15px 0 7px;
border-left: 1px solid #EEE;
padding: 10px 15px;
margin: 5px 0 10px 5px;
background: #f9f9f9;
display: none;
pre {
border: none;
background: inherit;
padding: 0;
margin: 0;
}
}
.commit-row-info {
......
......@@ -7,3 +7,7 @@
.member-search-form {
float: left;
}
.milestone-row {
@include str-truncated(90%);
}
......@@ -53,13 +53,9 @@ header {
font-size: 18px;
.app_logo { margin-left: -15px; }
.title {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: top;
white-space: nowrap;
max-width: 70%;
@include str-truncated(70%);
}
.navbar-collapse {
......@@ -130,6 +126,7 @@ header {
margin: 0;
margin-left: 5px;
@include header-font;
@include str-truncated(37%);
}
.profile-pic {
......@@ -254,7 +251,7 @@ header {
.search .search-input {
width: 300px;
&:focus {
width: 400px;
width: 330px;
}
}
......@@ -262,7 +259,7 @@ header {
.search .search-input {
width: 200px;
&:focus {
width: 300px;
width: 230px;
}
}
}
......
......@@ -28,6 +28,7 @@
}
td {
border-color: #F1F1F1 !important;
border-bottom: 1px solid;
}
&:hover {
td {
......
......@@ -6,7 +6,7 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
end
def create
@broadcast_message = BroadcastMessage.new(params[:broadcast_message])
@broadcast_message = BroadcastMessage.new(broadcast_message_params)
if @broadcast_message.save
redirect_to admin_broadcast_messages_path, notice: 'Broadcast Message was successfully created.'
......@@ -29,4 +29,11 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
def broadcast_messages
@broadcast_messages ||= BroadcastMessage.order("starts_at DESC").page(params[:page])
end
def broadcast_message_params
params.require(:broadcast_message).permit(
:alert_type, :color, :ends_at, :font,
:message, :starts_at
)
end
end
......@@ -20,7 +20,7 @@ class Admin::GroupsController < Admin::ApplicationController
end
def create
@group = Group.new(params[:group])
@group = Group.new(group_params)
@group.path = @group.name.dup.parameterize if @group.name
if @group.save
......@@ -32,7 +32,7 @@ class Admin::GroupsController < Admin::ApplicationController
end
def update
if @group.update_attributes(params[:group])
if @group.update_attributes(group_params)
redirect_to [:admin, @group], notice: 'Group was successfully updated.'
else
render "edit"
......@@ -56,4 +56,8 @@ class Admin::GroupsController < Admin::ApplicationController
def group
@group = Group.find_by(path: params[:id])
end
def group_params
params.require(:group).permit(:name, :description, :path, :avatar)
end
end
......@@ -5,7 +5,7 @@ class Admin::HooksController < Admin::ApplicationController
end
def create
@hook = SystemHook.new(params[:hook])
@hook = SystemHook.new(hook_params)
if @hook.save
redirect_to admin_hooks_path, notice: 'Hook was successfully created.'
......@@ -37,4 +37,8 @@ class Admin::HooksController < Admin::ApplicationController
redirect_to :back
end
def hook_params
params.require(:hook).permit(:url)
end
end
......@@ -13,7 +13,7 @@ class Admin::UsersController < Admin::ApplicationController
end
def new
@user = User.build_user
@user = User.new
end
def edit
......@@ -37,15 +37,12 @@ class Admin::UsersController < Admin::ApplicationController
end
def create
admin = params[:user].delete("admin")
opts = {
force_random_password: true,
password_expires_at: Time.now
}
@user = User.build_user(params[:user].merge(opts), as: :admin)
@user.admin = (admin && admin.to_i > 0)
@user = User.new(user_params.merge(opts))
@user.created_by_id = current_user.id
@user.generate_password
@user.skip_confirmation!
......@@ -62,19 +59,15 @@ class Admin::UsersController < Admin::ApplicationController
end
def update
admin = params[:user].delete("admin")
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
if admin.present?
user.admin = !admin.to_i.zero?
if params[:user][:password].present?
user_params.merge(
password: params[:user][:password],
password_confirmation: params[:user][:password_confirmation],
)
end
respond_to do |format|
if user.update_attributes(params[:user], as: :admin)
if user.update_attributes(user_params)
user.confirm!
format.html { redirect_to [:admin, user], notice: 'User was successfully updated.' }
format.json { head :ok }
......@@ -115,4 +108,13 @@ class Admin::UsersController < Admin::ApplicationController
def user
@user ||= User.find_by!(username: params[:id])
end
def user_params
params.require(:user).permit(
:email, :remember_me, :bio, :name, :username,
:skype, :linkedin, :twitter, :website_url, :color_scheme_id, :theme_id, :force_random_password,
:extern_uid, :provider, :password_expires_at, :avatar, :hide_no_ssh_key,
:projects_limit, :can_create_group, :admin
)
end
end
require 'gon'
class ApplicationController < ActionController::Base
before_filter :authenticate_user_from_token!
before_filter :authenticate_user!
before_filter :reject_blocked!
before_filter :check_password_expiration
......@@ -28,6 +29,25 @@ class ApplicationController < ActionController::Base
protected
# From https://github.com/plataformatec/devise/wiki/How-To:-Simple-Token-Authentication-Example
# https://gist.github.com/josevalim/fb706b1e933ef01e4fb6
def authenticate_user_from_token!
user_token = if params[:authenticity_token].presence
params[:authenticity_token].presence
elsif params[:private_token].presence
params[:private_token].presence
end
user = user_token && User.find_by_authentication_token(user_token.to_s)
if user
# Notice we are passing store false, so the user is not
# actually stored in the session and a token is needed
# for every request. If you want the token to work as a
# sign in token, you can simply remove store: false.
sign_in user, store: false
end
end
def log_exception(exception)
application_trace = ActionDispatch::ExceptionWrapper.new(env, exception).application_trace
application_trace.map!{ |t| " #{t}\n" }
......@@ -227,8 +247,7 @@ class ApplicationController < ActionController::Base
end
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email, :password, :login, :remember_me) }
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :name, :password, :password_confirmation) }
devise_parameter_sanitizer.sanitize(:sign_in) { |u| u.permit(:username, :email, :password, :login, :remember_me) }
end
def hexdigest(string)
......
class Groups::MilestonesController < ApplicationController
layout 'group'
before_filter :authorize_group_milestone!, only: :update
def index
project_milestones = case params[:status]
when 'all'; status
when 'closed'; status('closed')
else status('active')
end
@group_milestones = Milestones::GroupService.new(project_milestones).execute
@group_milestones = Kaminari.paginate_array(@group_milestones).page(params[:page]).per(30)
end
def show
project_milestones = Milestone.where(project_id: group.projects).order("due_date ASC")
@group_milestone = Milestones::GroupService.new(project_milestones).milestone(title)
end
def update
project_milestones = Milestone.where(project_id: group.projects).order("due_date ASC")
@group_milestones = Milestones::GroupService.new(project_milestones).milestone(title)
@group_milestones.milestones.each do |milestone|
Milestones::UpdateService.new(milestone.project, current_user, params[:milestone]).execute(milestone)
end
respond_to do |format|
format.js
format.html do
redirect_to group_milestones_path(group)
end
end
end
private
def group
@group ||= Group.find_by(path: params[:group_id])
end
def title
params[:title]
end
def status(state = nil)
conditions = { project_id: group.projects }
conditions.reverse_merge!(state: state) if state
Milestone.where(conditions).order("title ASC")
end
def authorize_group_milestone!
return render_404 unless can?(current_user, :manage_group, group)
end
end
......@@ -22,7 +22,7 @@ class GroupsController < ApplicationController
end
def create
@group = Group.new(params[:group])
@group = Group.new(group_params)
@group.path = @group.name.dup.parameterize if @group.name
if @group.save
......@@ -86,7 +86,7 @@ class GroupsController < ApplicationController
end
def update
if @group.update_attributes(params[:group])
if @group.update_attributes(group_params)
redirect_to edit_group_path(@group), notice: 'Group was successfully updated.'
else
render action: "edit"
......@@ -161,4 +161,8 @@ class GroupsController < ApplicationController
params[:state] = 'opened' if params[:state].blank?
params[:group_id] = @group.id
end
def group_params
params.require(:group).permit(:name, :description, :path, :avatar, :ldap_access, :ldap_cn)
end
end
......@@ -7,7 +7,7 @@ class Profiles::EmailsController < ApplicationController
end
def create
@email = current_user.emails.new(params[:email])
@email = current_user.emails.new(email_params)
flash[:alert] = @email.errors.full_messages.first unless @email.save
......@@ -23,4 +23,10 @@ class Profiles::EmailsController < ApplicationController
format.js { render nothing: true }
end
end
private
def email_params
params.require(:email).permit(:email)
end
end
......@@ -15,7 +15,7 @@ class Profiles::KeysController < ApplicationController
end
def create
@key = current_user.keys.new(params[:key])
@key = current_user.keys.new(key_params)
if @key.save
redirect_to profile_key_path(@key)
......@@ -53,4 +53,9 @@ class Profiles::KeysController < ApplicationController
end
end
private
def key_params
params.require(:key).permit(:title, :key)
end
end
......@@ -11,8 +11,8 @@ class Profiles::PasswordsController < ApplicationController
end
def create
new_password = params[:user][:password]
new_password_confirmation = params[:user][:password_confirmation]
new_password = user_params[:password]
new_password_confirmation = user_params[:password_confirmation]
result = @user.update_attributes(
password: new_password,
......@@ -31,11 +31,11 @@ class Profiles::PasswordsController < ApplicationController
end
def update
password_attributes = params[:user].select do |key, value|
password_attributes = user_params.select do |key, value|
%w(password password_confirmation).include?(key.to_s)
end
unless @user.valid_password?(params[:user][:current_password])
unless @user.valid_password?(user_params[:current_password])
redirect_to edit_profile_password_path, alert: 'You must provide a valid current password'
return
end
......@@ -74,4 +74,8 @@ class Profiles::PasswordsController < ApplicationController
def authorize_change_password!
return render_404 if @user.ldap_user?
end
def user_params
params.require(:user).permit(:current_password, :password, :password_confirmation)
end
end
......@@ -14,9 +14,9 @@ class ProfilesController < ApplicationController
end
def update
params[:user].delete(:email) if @user.ldap_user?
user_params.except!(:email) if @user.ldap_user?
if @user.update_attributes(params[:user])
if @user.update_attributes(user_params)
flash[:notice] = "Profile was successfully updated"
else
flash[:alert] = "Failed to update profile"
......@@ -41,7 +41,7 @@ class ProfilesController < ApplicationController
end
def update_username
@user.update_attributes(username: params[:user][:username])
@user.update_attributes(username: user_params[:username])
respond_to do |format|
format.js
......@@ -57,4 +57,12 @@ class ProfilesController < ApplicationController
def authorize_change_username!
return render_404 unless @user.can_change_username?
end
def user_params
params.require(:user).permit(
:email, :password, :password_confirmation, :bio, :name, :username,
:skype, :linkedin, :twitter, :website_url, :color_scheme_id, :theme_id,
:avatar, :hide_no_ssh_key,
)
end
end
......@@ -30,8 +30,12 @@ class Projects::BlobController < Projects::ApplicationController
def blob
@blob ||= @repository.blob_at(@commit.id, @path)
return not_found! unless @blob
if @blob
@blob
elsif tree.entries.any?
redirect_to project_tree_path(@project, File.join(@ref, @path)) and return
else
return not_found!
end
end
end
......@@ -22,7 +22,7 @@ class Projects::DeployKeysController < Projects::ApplicationController
end
def create
@key = DeployKey.new(params[:deploy_key])
@key = DeployKey.new(deploy_key_params)
if @key.valid? && @project.deploy_keys << @key
redirect_to project_deploy_keys_path(@project)
......@@ -58,4 +58,8 @@ class Projects::DeployKeysController < Projects::ApplicationController
def available_keys
@available_keys ||= current_user.accessible_deploy_keys
end
def deploy_key_params
params.require(:deploy_key).permit(:key, :title)
end
end
......@@ -28,8 +28,6 @@ class Projects::EditTreeController < Projects::BaseTreeController
def preview
@content = params[:content]
#FIXME workaround https://github.com/gitlabhq/gitlabhq/issues/5936
@content += "\n" if @blob.data.end_with?("\n")
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3',
include_diff_info: true)
......
......@@ -12,7 +12,7 @@ class Projects::HooksController < Projects::ApplicationController
end
def create
@hook = @project.hooks.new(params[:hook])
@hook = @project.hooks.new(hook_params)
@hook.save
if @hook.valid?
......@@ -40,4 +40,8 @@ class Projects::HooksController < Projects::ApplicationController
def hook
@hook ||= @project.hooks.find(params[:id])
end
def hook_params
params.require(:hook).permit(:url, :push_events, :issues_events, :merge_requests_events, :tag_push_events)
end
end
......@@ -42,7 +42,11 @@ class Projects::IssuesController < Projects::ApplicationController
end
def new
@issue = @project.issues.new(params[:issue])
params[:issue] ||= ActionController::Parameters.new(
assignee_id: ""
)
@issue = @project.issues.new(issue_params)
respond_with(@issue)
end
......@@ -59,7 +63,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def create
@issue = Issues::CreateService.new(project, current_user, params[:issue]).execute
@issue = Issues::CreateService.new(project, current_user, issue_params).execute
respond_to do |format|
format.html do
......@@ -76,7 +80,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def update
@issue = Issues::UpdateService.new(project, current_user, params[:issue]).execute(issue)
@issue = Issues::UpdateService.new(project, current_user, issue_params).execute(issue)
respond_to do |format|
format.js
......@@ -144,4 +148,11 @@ class Projects::IssuesController < Projects::ApplicationController
raise ActiveRecord::RecordNotFound.new
end
end
def issue_params
params.require(:issue).permit(
:title, :assignee_id, :position, :description,
:milestone_id, :label_list, :state_event
)
end
end
......@@ -60,7 +60,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def new
@merge_request = MergeRequest.new(params[:merge_request])
params[:merge_request] ||= ActionController::Parameters.new(
source_project: @project
)
@merge_request = MergeRequest.new(merge_request_params)
@merge_request.source_project = @project unless @merge_request.source_project
@merge_request.target_project ||= (@project.forked_from_project || @project)
@target_branches = @merge_request.target_project.nil? ? [] : @merge_request.target_project.repository.branch_names
......@@ -111,7 +115,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def create
@target_branches ||= []
@merge_request = MergeRequests::CreateService.new(project, current_user, params[:merge_request]).execute
@merge_request = MergeRequests::CreateService.new(project, current_user, merge_request_params).execute
if @merge_request.valid?
redirect_to project_merge_request_path(@merge_request.target_project, @merge_request), notice: 'Merge request was successfully created.'
......@@ -123,7 +127,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def update
@merge_request = MergeRequests::UpdateService.new(project, current_user, params[:merge_request]).execute(@merge_request)
@merge_request = MergeRequests::UpdateService.new(project, current_user, merge_request_params).execute(@merge_request)
if @merge_request.valid?
respond_to do |format|
......@@ -264,4 +268,12 @@ class Projects::MergeRequestsController < Projects::ApplicationController
can?(current_user, action, project)
end
def merge_request_params
params.require(:merge_request).permit(
:title, :assignee_id, :source_project_id, :source_branch,
:target_project_id, :target_branch, :milestone_id,
:state_event, :description, :label_list
)
end
end
......@@ -37,7 +37,7 @@ class Projects::MilestonesController < Projects::ApplicationController
end
def create
@milestone = Milestones::CreateService.new(project, current_user, params[:milestone]).execute
@milestone = Milestones::CreateService.new(project, current_user, milestone_params).execute
if @milestone.save
redirect_to project_milestone_path(@project, @milestone)
......@@ -47,7 +47,7 @@ class Projects::MilestonesController < Projects::ApplicationController
end
def update
@milestone = Milestones::UpdateService.new(project, current_user, params[:milestone]).execute(milestone)
@milestone = Milestones::UpdateService.new(project, current_user, milestone_params).execute(milestone)
respond_to do |format|
format.js
......@@ -105,4 +105,8 @@ class Projects::MilestonesController < Projects::ApplicationController
def module_enabled
return render_404 unless @project.issues_enabled
end
def milestone_params
params.require(:milestone).permit(:title, :description, :due_date, :state_event)
end
end
......@@ -21,7 +21,7 @@ class Projects::NotesController < Projects::ApplicationController
end
def create
@note = Notes::CreateService.new(project, current_user, params[:note]).execute
@note = Notes::CreateService.new(project, current_user, note_params).execute
respond_to do |format|
format.json { render_note_json(@note) }
......@@ -30,7 +30,7 @@ class Projects::NotesController < Projects::ApplicationController
end
def update
note.update_attributes(params[:note])
note.update_attributes(note_params)
note.reset_events_cache
respond_to do |format|
......@@ -109,4 +109,11 @@ class Projects::NotesController < Projects::ApplicationController
def authorize_admin_note!
return access_denied! unless can?(current_user, :admin_note, note)
end
def note_params
params.require(:note).permit(
:note, :noteable, :noteable_id, :noteable_type, :project_id,
:attachment, :line_code, :commit_id
)
end
end
......@@ -11,7 +11,7 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
end
def create
@project.protected_branches.create(params[:protected_branch])
@project.protected_branches.create(protected_branch_params)
redirect_to project_protected_branches_path(@project)
end
......@@ -23,4 +23,10 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
format.js { render nothing: true }
end
end
private
def protected_branch_params
params.require(:protected_branch).permit(:name)
end
end
......@@ -22,6 +22,7 @@ class Projects::RepositoriesController < Projects::ApplicationController
if file_path
# Send file to user
response.headers["Content-Length"] = File.open(file_path).size.to_s
send_file file_path
else
render_404
......
......@@ -16,7 +16,7 @@ class Projects::ServicesController < Projects::ApplicationController
end
def update
if @service.update_attributes(params[:service])
if @service.update_attributes(service_params)
redirect_to edit_project_service_path(@project, @service.to_param)
else
render 'edit'
......@@ -36,4 +36,11 @@ class Projects::ServicesController < Projects::ApplicationController
def service
@service ||= @project.services.find { |service| service.to_param == params[:id] }
end
def service_params
params.require(:service).permit(
:title, :token, :type, :active, :api_key, :subdomain,
:room, :recipients, :project_url
)
end
end
......@@ -25,7 +25,7 @@ class Projects::SnippetsController < Projects::ApplicationController
end
def create
@snippet = @project.snippets.build(params[:project_snippet])
@snippet = @project.snippets.build(snippet_params)
@snippet.author = current_user
if @snippet.save
......@@ -39,7 +39,7 @@ class Projects::SnippetsController < Projects::ApplicationController
end
def update
if @snippet.update_attributes(params[:project_snippet])
if @snippet.update_attributes(snippet_params)
redirect_to project_snippet_path(@project, @snippet)
else
respond_with(@snippet)
......@@ -86,4 +86,8 @@ class Projects::SnippetsController < Projects::ApplicationController
def module_enabled
return render_404 unless @project.snippets_enabled
end
def snippet_params
params.require(:project_snippet).permit(:title, :content, :file_name, :private)
end
end
......@@ -27,7 +27,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
def update
@user_project_relation = project.users_projects.find_by(user_id: member)
@user_project_relation.update_attributes(params[:team_member])
@user_project_relation.update_attributes(member_params)
unless @user_project_relation.valid?
flash[:alert] = "User should have at least one role"
......@@ -67,4 +67,8 @@ class Projects::TeamMembersController < Projects::ApplicationController
def member
@member ||= User.find_by(username: params[:id])
end
def member_params
params.require(:team_member).permit(:user_id, :project_access)
end
end
# Controller for viewing a repository's file structure
class Projects::TreeController < Projects::BaseTreeController
def show
return not_found! if tree.entries.empty?
if tree.entries.empty?
if @repository.blob_at(@commit.id, @path)
redirect_to project_blob_path(@project, File.join(@ref, @path)) and return
else
return not_found!
end
end
respond_to do |format|
format.html
......
......@@ -20,7 +20,7 @@ class ProjectsController < ApplicationController
end
def create
@project = ::Projects::CreateService.new(current_user, params[:project]).execute
@project = ::Projects::CreateService.new(current_user, project_params).execute
flash[:notice] = 'Project was successfully created.' if @project.saved?
respond_to do |format|
......@@ -29,7 +29,7 @@ class ProjectsController < ApplicationController
end
def update
status = ::Projects::UpdateService.new(@project, current_user, params).execute
status = ::Projects::UpdateService.new(@project, current_user, project_params).execute
respond_to do |format|
if status
......@@ -44,7 +44,7 @@ class ProjectsController < ApplicationController
end
def transfer
::Projects::TransferService.new(project, current_user, params[:project]).execute
::Projects::TransferService.new(project, current_user, project_params).execute
end
def show
......@@ -85,7 +85,7 @@ class ProjectsController < ApplicationController
redirect_to import_project_path(@project)
end
@project.import_url = params[:project][:import_url]
@project.import_url = project_params[:import_url]
if @project.save
@project.reload
......@@ -185,4 +185,12 @@ class ProjectsController < ApplicationController
def user_layout
current_user ? "projects" : "public_projects"
end
def project_params
params.require(:project).permit(
:name, :path, :description, :issues_tracker, :label_list,
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id,
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :merge_requests_template
)
end
end
......@@ -13,7 +13,14 @@ class RegistrationsController < Devise::RegistrationsController
def build_resource(hash=nil)
super
self.resource.with_defaults
end
def after_sign_up_path_for resource
new_user_session_path
end
def after_inactive_sign_up_path_for resource
new_user_session_path
end
private
......@@ -21,4 +28,8 @@ class RegistrationsController < Devise::RegistrationsController
def signup_enabled?
redirect_to new_user_session_path unless Gitlab.config.gitlab.signup_enabled
end
def sign_up_params
params.require(:user).permit(:username, :email, :name, :password, :password_confirmation)
end
end
......@@ -51,7 +51,7 @@ class SnippetsController < ApplicationController
end
def create
@snippet = PersonalSnippet.new(params[:personal_snippet])
@snippet = PersonalSnippet.new(snippet_params)
@snippet.author = current_user
if @snippet.save
......@@ -65,7 +65,7 @@ class SnippetsController < ApplicationController
end
def update
if @snippet.update_attributes(params[:personal_snippet])
if @snippet.update_attributes(snippet_params)
redirect_to snippet_path(@snippet)
else
respond_with @snippet
......@@ -109,4 +109,8 @@ class SnippetsController < ApplicationController
def set_title
@title = 'Snippets'
end
def snippet_params
params.require(:personal_snippet).permit(:title, :content, :file_name, :private)
end
end
......@@ -14,7 +14,7 @@ class UsersGroupsController < ApplicationController
def update
@member = @group.users_groups.find(params[:id])
@member.update_attributes(params[:users_group])
@member.update_attributes(member_params)
end
def destroy
......@@ -41,4 +41,8 @@ class UsersGroupsController < ApplicationController
return render_404
end
end
def member_params
params.require(:users_group).permit(:group_access, :user_id)
end
end
......@@ -14,7 +14,7 @@ class NotesFinder
project.issues.find(target_id).notes.inc_author.fresh
when "merge_request"
project.merge_requests.find(target_id).mr_and_commit_notes.inc_author.fresh
when "snippet"
when "snippet", "project_snippet"
project.snippets.find(target_id).notes.fresh
else
raise 'invalid target_type'
......
......@@ -180,6 +180,17 @@ module CommitsHelper
return old_lines, new_lines
end
def link_to_browse_code(project, commit)
if current_controller?(:projects, :commits)
if @repo.blob_at(commit.id, @path)
return link_to "Browse File »", project_blob_path(project, tree_join(commit.id, @path)), class: "pull-right"
elsif @path.present?
return link_to "Browse Dir »", project_tree_path(project, tree_join(commit.id, @path)), class: "pull-right"
end
end
link_to "Browse Code »", project_tree_path(project, commit), class: "pull-right"
end
protected
# Private: Returns a link to a person. If the person has a matching user and
......
......@@ -35,4 +35,42 @@ module DashboardHelper
path << "?#{options.to_param}"
path
end
def assigned_entities_count(current_user, entity, scope = nil)
items = current_user.send("assigned_" + entity.pluralize).opened
if scope.kind_of?(Group)
items = items.of_group(scope)
elsif scope.kind_of?(Project)
items = items.of_projects(scope)
end
items.count
end
def authored_entities_count(current_user, entity, scope = nil)
items = current_user.send(entity.pluralize).opened
if scope.kind_of?(Group)
items = items.of_group(scope)
elsif scope.kind_of?(Project)
items = items.of_projects(scope)
end
items.count
end
def authorized_entities_count(current_user, entity, scope = nil)
items = entity.classify.constantize.opened
if scope.kind_of?(Group)
items = items.of_group(scope)
elsif scope.kind_of?(Project)
items = items.of_projects(scope)
else
items = items.of_projects(current_user.authorized_projects)
end
items.count
end
end
......@@ -64,7 +64,16 @@ module EventsHelper
project_issue_url(event.project, event.issue)
elsif event.merge_request?
project_merge_request_url(event.project, event.merge_request)
elsif event.note?
if event.note_target
if event.note_commit?
project_commit_path(event.project, event.note_commit_id, anchor: dom_id(event.target))
elsif event.note_project_snippet?
project_snippet_path(event.project, event.note_target)
else
event_note_target_path(event)
end
end
elsif event.push?
if event.push_with_commits?
if event.commits_count > 1
......@@ -83,6 +92,10 @@ module EventsHelper
render "events/event_issue", issue: event.issue
elsif event.push?
render "events/event_push", event: event
elsif event.merge_request?
render "events/event_merge_request", merge_request: event.merge_request
elsif event.note?
render "events/event_note", note: event.note
end
end
......
......@@ -138,7 +138,7 @@ module GitlabMarkdownHelper
# If we are at doc/api/README.md and the README.md contains relative links like [Users](users.md)
# this takes the request path(doc/api/README.md), and replaces the README.md with users.md so the path looks like doc/api/users.md
# If we are at doc/api and the README.md shown in below the tree view
# this takes the rquest path(doc/api) and adds users.md so the path looks like doc/api/users.md
# this takes the request path(doc/api) and adds users.md so the path looks like doc/api/users.md
def build_nested_path(path, request_path)
return request_path if path == ""
return path unless request_path
......
......@@ -31,6 +31,17 @@ module GroupsHelper
end
title
end
def group_filter_path(entity, options={})
exist_opts = {
status: params[:status]
}
options = exist_opts.merge(options)
path = request.path
path << "?#{options.to_param}"
path
end
end
......@@ -4,8 +4,8 @@ module Emails
@issue = Issue.find(issue_id)
@project = @issue.project
@target_url = project_issue_url(@project, @issue)
set_message_id("issue_#{issue_id}")
mail(from: sender(@issue.author_id),
mail_new_thread(@issue,
from: sender(@issue.author_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
end
......@@ -15,8 +15,8 @@ module Emails
@previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
@project = @issue.project
@target_url = project_issue_url(@project, @issue)
set_reference("issue_#{issue_id}")
mail(from: sender(updated_by_user_id),
mail_answer_thread(@issue,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
end
......@@ -26,8 +26,8 @@ module Emails
@project = @issue.project
@updated_by = User.find updated_by_user_id
@target_url = project_issue_url(@project, @issue)
set_reference("issue_#{issue_id}")
mail(from: sender(updated_by_user_id),
mail_answer_thread(@issue,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
end
......@@ -38,8 +38,8 @@ module Emails
@project = @issue.project
@updated_by = User.find updated_by_user_id
@target_url = project_issue_url(@project, @issue)
set_reference("issue_#{issue_id}")
mail(from: sender(updated_by_user_id),
mail_answer_thread(@issue,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
end
......
......@@ -4,8 +4,8 @@ module Emails
@merge_request = MergeRequest.find(merge_request_id)
@project = @merge_request.project
@target_url = project_merge_request_url(@project, @merge_request)
set_message_id("merge_request_#{merge_request_id}")
mail(from: sender(@merge_request.author_id),
mail_new_thread(@merge_request,
from: sender(@merge_request.author_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
......@@ -15,8 +15,8 @@ module Emails
@previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
@project = @merge_request.project
@target_url = project_merge_request_url(@project, @merge_request)
set_reference("merge_request_#{merge_request_id}")
mail(from: sender(updated_by_user_id),
mail_answer_thread(@merge_request,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
......@@ -26,8 +26,8 @@ module Emails
@updated_by = User.find updated_by_user_id
@project = @merge_request.project
@target_url = project_merge_request_url(@project, @merge_request)
set_reference("merge_request_#{merge_request_id}")
mail(from: sender(updated_by_user_id),
mail_answer_thread(@merge_request,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
......@@ -36,10 +36,22 @@ module Emails
@merge_request = MergeRequest.find(merge_request_id)
@project = @merge_request.project
@target_url = project_merge_request_url(@project, @merge_request)
mail_answer_thread(@merge_request,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
def merge_request_status_email(recipient_id, merge_request_id, status, updated_by_user_id)
@merge_request = MergeRequest.find(merge_request_id)
@mr_status = status
@project = @merge_request.project
@updated_by = User.find updated_by_user_id
@target_url = project_merge_request_url(@project, @merge_request)
set_reference("merge_request_#{merge_request_id}")
mail(from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
subject: subject("#{@merge_request.title} (##{@merge_request.iid}) #{@mr_status}"))
end
end
......
......@@ -5,7 +5,8 @@ module Emails
@commit = @note.noteable
@project = @note.project
@target_url = project_commit_url(@project, @commit, anchor: "note_#{@note.id}")
mail(from: sender(@note.author_id),
mail_answer_thread(@commit,
from: sender(@note.author_id),
to: recipient(recipient_id),
subject: subject("#{@commit.title} (#{@commit.short_id})"))
end
......@@ -15,8 +16,8 @@ module Emails
@issue = @note.noteable
@project = @note.project
@target_url = project_issue_url(@project, @issue, anchor: "note_#{@note.id}")
set_reference("issue_#{@issue.id}")
mail(from: sender(@note.author_id),
mail_answer_thread(@issue,
from: sender(@note.author_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
end
......@@ -26,8 +27,8 @@ module Emails
@merge_request = @note.noteable
@project = @note.project
@target_url = project_merge_request_url(@project, @merge_request, anchor: "note_#{@note.id}")
set_reference("merge_request_#{@merge_request.id}")
mail(from: sender(@note.author_id),
mail_answer_thread(@merge_request,
from: sender(@note.author_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
......
class Notify < ActionMailer::Base
include ActionDispatch::Routing::PolymorphicRoutes
include Emails::Issues
include Emails::MergeRequests
include Emails::Notes
......@@ -53,14 +55,6 @@ class Notify < ActionMailer::Base
end
end
# Set the Message-ID header field
#
# local_part - The local part of the message ID
#
def set_message_id(local_part)
headers["Message-ID"] = "<#{local_part}@#{Gitlab.config.gitlab.host}>"
end
# Set the References header field
#
# local_part - The local part of the referenced message ID
......@@ -93,4 +87,40 @@ class Notify < ActionMailer::Base
subject << extra.join(' | ') if extra.present?
subject
end
# Return a string suitable for inclusion in the 'Message-Id' mail header.
#
# The message-id is generated from the unique URL to a model object.
def message_id(model)
model_name = model.class.model_name.singular_route_key
"<#{model_name}_#{model.id}@#{Gitlab.config.gitlab.host}>"
end
# Send an email that starts a new conversation thread,
# with headers suitable for grouping by thread in email clients.
#
# See: mail_answer_thread
def mail_new_thread(model, headers = {}, &block)
headers['Message-ID'] = message_id(model)
mail(headers, &block)
end
# Send an email that responds to an existing conversation thread,
# with headers suitable for grouping by thread in email clients.
#
# For grouping emails by thread, email clients heuristics require the answers to:
#
# * have a subject that begin by 'Re: '
# * have a 'In-Reply-To' or 'References' header that references the original 'Message-ID'
#
def mail_answer_thread(model, headers = {}, &block)
headers['In-Reply-To'] = message_id(model)
headers['References'] = message_id(model)
if (headers[:subject])
headers[:subject].prepend('Re: ')
end
mail(headers, &block)
end
end
......@@ -14,8 +14,6 @@
#
class BroadcastMessage < ActiveRecord::Base
attr_accessible :alert_type, :color, :ends_at, :font, :message, :starts_at
validates :message, presence: true
validates :starts_at, presence: true
validates :ends_at, presence: true
......
module TokenAuthenticatable
extend ActiveSupport::Concern
module ClassMethods
def find_by_authentication_token(authentication_token = nil)
if authentication_token
where(authentication_token: authentication_token).first
end
end
end
def ensure_authentication_token
if authentication_token.blank?
self.authentication_token = generate_authentication_token
end
end
def reset_authentication_token!
self.authentication_token = generate_authentication_token
save
end
private
def generate_authentication_token
loop do
token = Devise.friendly_token
break token unless self.class.unscoped.where(authentication_token: token).first
end
end
end
......@@ -10,13 +10,10 @@
#
class DeployKeysProject < ActiveRecord::Base
attr_accessible :key_id, :project_id
belongs_to :project
belongs_to :deploy_key
validates :deploy_key_id, presence: true
validates :deploy_key_id, uniqueness: { scope: [:project_id], message: "already exists in project" }
validates :project_id, presence: true
end
......@@ -10,16 +10,8 @@
#
class Email < ActiveRecord::Base
attr_accessible :email, :user_id
#
# Relations
#
belongs_to :user
#
# Validations
#
validates :user_id, presence: true
validates :email, presence: true, email: { strict_mode: true }, uniqueness: true
validate :unique_email, if: ->(email) { email.email_changed? }
......
......@@ -15,9 +15,6 @@
#
class Event < ActiveRecord::Base
attr_accessible :project, :action, :data, :author_id, :project_id,
:target_id, :target_type
default_scope { where.not(author_id: nil) }
CREATED = 1
......@@ -33,6 +30,7 @@ class Event < ActiveRecord::Base
delegate :name, :email, to: :author, prefix: true, allow_nil: true
delegate :title, to: :issue, prefix: true, allow_nil: true
delegate :title, to: :merge_request, prefix: true, allow_nil: true
delegate :title, to: :note, prefix: true, allow_nil: true
belongs_to :author, class_name: "User"
belongs_to :project
......@@ -150,6 +148,10 @@ class Event < ActiveRecord::Base
target if target_type == "MergeRequest"
end
def note
target if target_type == "Note"
end
def action_name
if closed?
"closed"
......
......@@ -10,10 +10,6 @@
#
class ForkedProjectLink < ActiveRecord::Base
attr_accessible :forked_from_project_id, :forked_to_project_id
# Relations
belongs_to :forked_to_project, class_name: Project
belongs_to :forked_from_project, class_name: Project
end
......@@ -19,19 +19,14 @@ require 'file_size_validator'
class Group < Namespace
has_many :users_groups, dependent: :destroy
has_many :users, through: :users_groups
has_many :project_group_links, dependent: :destroy
has_many :shared_projects, through: :project_group_links, source: :project
attr_accessible :ldap_cn, :ldap_access
validates :ldap_access,
inclusion: { in: UsersGroup.group_access_roles.values },
presence: true,
if: ->(group) { group.ldap_cn.present? }
attr_accessible :avatar
validate :avatar_type, if: ->(user) { user.avatar_changed? }
validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
......
class GroupMilestone
def initialize(title, milestones)
@title = title
@milestones = milestones
end
def title
@title
end
def safe_title
@title.parameterize
end
def milestones
@milestones
end
def projects
milestones.map { |milestone| milestone.project }
end
def issue_count
milestones.map { |milestone| milestone.issues.count }.sum
end
def merge_requests_count
milestones.map { |milestone| milestone.merge_requests.count }.sum
end
def open_items_count
milestones.map { |milestone| milestone.open_items_count }.sum
end
def closed_items_count
milestones.map { |milestone| milestone.closed_items_count }.sum
end
def total_items_count
milestones.map { |milestone| milestone.total_items_count }.sum
end
def percent_complete
((closed_items_count * 100) / total_items_count).abs
rescue ZeroDivisionError
100
end
def state
state = milestones.map { |milestone| milestone.state }
if state.count('active') == state.size
'active'
else
'closed'
end
end
def active?
state == 'active'
end
def closed?
state == 'closed'
end
def issues
@group_issues ||= milestones.map { |milestone| milestone.issues }.flatten.group_by(&:state)
end
def merge_requests
@group_merge_requests ||= milestones.map { |milestone| milestone.merge_requests }.flatten.group_by(&:state)
end
def participants
milestones.map { |milestone| milestone.participants.uniq }.reject(&:empty?).flatten
end
def opened_issues
issues.values_at("opened", "reopened").compact.flatten
end
def closed_issues
issues['closed']
end
def opened_merge_requests
merge_requests.values_at("opened", "reopened").compact.flatten
end
def closed_merge_requests
merge_requests.values_at("closed", "merged", "locked").compact.flatten
end
end
......@@ -33,9 +33,6 @@ class Issue < ActiveRecord::Base
scope :of_group, ->(group) { where(project_id: group.project_ids) }
scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) }
attr_accessible :title, :assignee_id, :position, :description,
:milestone_id, :label_list, :state_event
acts_as_taggable_on :labels
scope :cared, ->(user) { where(assignee_id: user) }
......
......@@ -19,8 +19,6 @@ class Key < ActiveRecord::Base
belongs_to :user
attr_accessible :key, :title
before_validation :strip_white_space, :generate_fingerpint
validates :title, presence: true, length: { within: 0..255 }
......
......@@ -36,10 +36,6 @@ class MergeRequest < ActiveRecord::Base
delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil
attr_accessible :title, :assignee_id, :source_project_id, :source_branch,
:target_project_id, :target_branch, :milestone_id,
:state_event, :description, :label_list
attr_accessor :should_remove_source_branch
# When this attribute is true some MR validation is ignored
......@@ -62,11 +58,11 @@ class MergeRequest < ActiveRecord::Base
transition closed: :reopened
end
event :lock do
event :lock_mr do
transition [:reopened, :opened] => :locked
end
event :unlock do
event :unlock_mr do
transition locked: :reopened
end
......@@ -297,6 +293,8 @@ class MergeRequest < ActiveRecord::Base
message << title.to_s
message << "\n\n"
message << description.to_s
message << "\n\n"
message << "See merge request !#{iid}"
message
end
......
......@@ -22,8 +22,6 @@ class MergeRequestDiff < ActiveRecord::Base
belongs_to :merge_request
attr_accessible :state, :st_commits, :st_diffs
delegate :target_branch, :source_branch, to: :merge_request, prefix: nil
state_machine :state, initial: :empty do
......
......@@ -16,8 +16,6 @@
class Milestone < ActiveRecord::Base
include InternalId
attr_accessible :title, :description, :due_date, :state_event
belongs_to :project
has_many :issues
has_many :merge_requests
......
......@@ -16,8 +16,6 @@
class Namespace < ActiveRecord::Base
include Gitlab::ShellAdapter
attr_accessible :name, :description, :path
has_many :projects, dependent: :destroy
belongs_to :owner, class_name: "User"
......@@ -25,12 +23,12 @@ class Namespace < ActiveRecord::Base
validates :name, presence: true, uniqueness: true,
length: { within: 0..255 },
format: { with: Gitlab::Regex.name_regex,
message: "only letters, digits, spaces & '_' '-' '.' allowed." }
message: Gitlab::Regex.name_regex_message }
validates :description, length: { within: 0..255 }
validates :path, uniqueness: { case_sensitive: false }, presence: true, length: { within: 1..255 },
exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.path_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
message: Gitlab::Regex.path_regex_message }
delegate :name, to: :owner, allow_nil: true, prefix: true
......
......@@ -25,8 +25,6 @@ class Note < ActiveRecord::Base
default_value_for :system, false
attr_accessible :note, :noteable, :noteable_id, :noteable_type, :project_id,
:attachment, :line_code, :commit_id
attr_mentionable :note
belongs_to :project
......@@ -63,13 +61,13 @@ class Note < ActiveRecord::Base
def create_status_change_note(noteable, project, author, status, source)
body = "_Status changed to #{status}#{' by ' + source.gfm_reference if source}_"
create({
create(
noteable: noteable,
project: project,
author: author,
note: body,
system: true
}, without_protection: true)
)
end
# +noteable+ was referenced from +mentioner+, by including GFM in either +mentioner+'s description or an associated Note.
......@@ -88,7 +86,7 @@ class Note < ActiveRecord::Base
note_options.merge!(noteable: noteable)
end
create(note_options, without_protection: true)
create(note_options)
end
def create_milestone_change_note(noteable, project, author, milestone)
......@@ -98,13 +96,13 @@ class Note < ActiveRecord::Base
"_Milestone changed to #{milestone.title}_"
end
create({
create(
noteable: noteable,
project: project,
author: author,
note: body,
system: true
}, without_protection: true)
)
end
def create_assignee_change_note(noteable, project, author, assignee)
......@@ -116,7 +114,7 @@ class Note < ActiveRecord::Base
author: author,
note: body,
system: true
}, without_protection: true)
})
end
def discussions_from_notes(notes)
......
......@@ -27,24 +27,20 @@
class Project < ActiveRecord::Base
include Gitlab::ShellAdapter
include Gitlab::VisibilityLevel
include Gitlab::ConfigHelper
extend Gitlab::ConfigHelper
extend Enumerize
default_value_for :archived, false
default_value_for :issues_enabled, true
default_value_for :merge_requests_enabled, true
default_value_for :wiki_enabled, true
default_value_for :visibility_level, gitlab_config_features.visibility_level
default_value_for :issues_enabled, gitlab_config_features.issues
default_value_for :merge_requests_enabled, gitlab_config_features.merge_requests
default_value_for :wiki_enabled, gitlab_config_features.wiki
default_value_for :wall_enabled, false
default_value_for :snippets_enabled, true
default_value_for :snippets_enabled, gitlab_config_features.snippets
ActsAsTaggableOn.strict_case_match = true
attr_accessible :name, :path, :description, :issues_tracker, :label_list,
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id,
:wiki_enabled, :visibility_level, :import_url, :last_activity_at,
:merge_requests_template, as: [:default, :admin]
attr_accessible :namespace_id, :creator_id, as: :admin
acts_as_taggable_on :labels, :issues_default_labels
attr_accessor :new_default_branch
......@@ -101,13 +97,16 @@ class Project < ActiveRecord::Base
validates :description, length: { maximum: 2000 }, allow_blank: true
validates :name, presence: true, length: { within: 0..255 },
format: { with: Gitlab::Regex.project_name_regex,
message: "only letters, digits, spaces & '_' '-' '.' allowed. Letter or digit should be first" }
message: Gitlab::Regex.project_regex_message }
validates :path, presence: true, length: { within: 0..255 },
exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.path_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter or digit should be first" }
message: Gitlab::Regex.path_regex_message }
validates :issues_enabled, :merge_requests_enabled,
:wiki_enabled, inclusion: { in: [true, false] }
validates :visibility_level,
exclusion: { in: gitlab_config.restricted_visibility_levels },
if: -> { gitlab_config.restricted_visibility_levels.any? }
validates :issues_tracker_id, length: { maximum: 255 }, allow_blank: true
validates :namespace, presence: true
validates_uniqueness_of :name, scope: :namespace_id
......@@ -251,7 +250,7 @@ class Project < ActiveRecord::Base
end
def check_limit
unless creator.can_create_project?
unless creator.can_create_project? or namespace.kind == 'group'
errors[:limit_reached] << ("Your project limit is #{creator.projects_limit} projects! Please contact your administrator to increase it")
end
rescue
......@@ -263,7 +262,7 @@ class Project < ActiveRecord::Base
end
def web_url
[Gitlab.config.gitlab.url, path_with_namespace].join("/")
[gitlab_config.url, path_with_namespace].join("/")
end
def web_url_without_protocol
......@@ -403,7 +402,11 @@ class Project < ActiveRecord::Base
services.each do |service|
# Call service hook only if it is active
begin
service.execute(data) if service.active
rescue => e
logger.error(e)
end
end
end
......@@ -488,7 +491,7 @@ class Project < ActiveRecord::Base
end
def http_url_to_repo
[Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
[gitlab_config.url, "/", path_with_namespace, ".git"].join('')
end
# Check if current branch name is marked as protected in the system
......
......@@ -18,8 +18,6 @@
class ProjectHook < WebHook
belongs_to :project
attr_accessible :push_events, :issues_events, :merge_requests_events, :tag_push_events
scope :push_hooks, -> { where(push_events: true) }
scope :tag_push_hooks, -> { where(tag_push_events: true) }
scope :issue_hooks, -> { where(issues_events: true) }
......
......@@ -18,8 +18,6 @@
#
class AssemblaService < Service
attr_accessible :subdomain
include HTTParty
validates :token, presence: true, if: :activated?
......
......@@ -18,8 +18,6 @@
#
class CampfireService < Service
attr_accessible :subdomain, :room
validates :token, presence: true, if: :activated?
def title
......
......@@ -18,8 +18,6 @@
#
class EmailsOnPushService < Service
attr_accessible :recipients
validates :recipients, presence: true, if: :activated?
def title
......
......@@ -18,8 +18,6 @@
#
class GitlabCiService < CiService
attr_accessible :project_url
validates :project_url, presence: true, if: :activated?
validates :token, presence: true, if: :activated?
......
......@@ -18,8 +18,6 @@
#
class HipchatService < Service
attr_accessible :room
validates :token, presence: true, if: :activated?
def title
......
......@@ -18,9 +18,6 @@
#
class SlackService < Service
attr_accessible :room
attr_accessible :subdomain
validates :room, presence: true, if: :activated?
validates :subdomain, presence: true, if: :activated?
validates :token, presence: true, if: :activated?
......
......@@ -12,8 +12,6 @@
class ProtectedBranch < ActiveRecord::Base
include Gitlab::ShellAdapter
attr_accessible :name
belongs_to :project
validates :name, presence: true
validates :project, presence: true
......
......@@ -242,4 +242,25 @@ class Repository
branches
end
end
def contributors
log = graph_log.group_by { |i| i[:author_email] }
log.map do |email, contributions|
contributor = Gitlab::Contributor.new
contributor.email = email
contributions.each do |contribution|
if contributor.name.blank?
contributor.name = contribution[:author_name]
end
contributor.commits += 1
contributor.additions += contribution[:additions] || 0
contributor.deletions += contribution[:deletions] || 0
end
contributor
end
end
end
......@@ -22,8 +22,6 @@
class Service < ActiveRecord::Base
default_value_for :active, false
attr_accessible :title, :token, :type, :active, :api_key
belongs_to :project
has_one :service_hook
......
......@@ -18,8 +18,6 @@
class Snippet < ActiveRecord::Base
include Linguist::BlobHelper
attr_accessible :title, :content, :file_name, :expires_at, :private
default_value_for :private, true
belongs_to :author, class_name: "User"
......
......@@ -50,31 +50,25 @@ require 'carrierwave/orm/activerecord'
require 'file_size_validator'
class User < ActiveRecord::Base
include Gitlab::ConfigHelper
extend Gitlab::ConfigHelper
include TokenAuthenticatable
default_value_for :admin, false
default_value_for :can_create_group, true
default_value_for :can_create_group, gitlab_config.default_can_create_group
default_value_for :can_create_team, false
default_value_for :hide_no_ssh_key, false
default_value_for :projects_limit, gitlab_config.default_projects_limit
default_value_for :theme_id, gitlab_config.default_theme
devise :database_authenticatable, :token_authenticatable, :lockable, :async,
devise :database_authenticatable, :lockable, :async,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, :confirmable, :registerable
attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :username,
:skype, :linkedin, :twitter, :website_url, :color_scheme_id, :theme_id, :force_random_password,
:extern_uid, :provider, :password_expires_at, :avatar, :hide_no_ssh_key,
as: [:default, :admin]
attr_accessible :projects_limit, :can_create_group,
as: :admin
attr_accessor :force_random_password
# Virtual attribute for authenticating by either username or email
attr_accessor :login
# Add login to attr_accessible
attr_accessible :login
#
# Relations
#
......@@ -120,7 +114,7 @@ class User < ActiveRecord::Base
validates :username, presence: true, uniqueness: { case_sensitive: false },
exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.username_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
message: Gitlab::Regex.username_regex_message }
validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true
validate :namespace_uniq, if: ->(user) { user.username_changed? }
......@@ -223,20 +217,8 @@ class User < ActiveRecord::Base
where('users.username = ? OR users.id = ?', name_or_id.to_s, name_or_id.to_i).first
end
def build_user(attrs = {}, options= {})
if options[:as] == :admin
User.new(defaults.merge(attrs.symbolize_keys), options)
else
User.new(attrs, options).with_defaults
end
end
def defaults
{
projects_limit: Gitlab.config.gitlab.default_projects_limit,
can_create_group: Gitlab.config.gitlab.default_can_create_group,
theme_id: Gitlab.config.gitlab.default_theme
}
def build_user(attrs = {})
User.new(attrs)
end
end
......@@ -315,7 +297,7 @@ class User < ActiveRecord::Base
end
def can_change_username?
Gitlab.config.gitlab.username_changing_enabled
gitlab_config.username_changing_enabled
end
def can_create_project?
......@@ -490,7 +472,7 @@ class User < ActiveRecord::Base
def avatar_url(size = nil)
if avatar.present?
URI::join(Gitlab.config.gitlab.url, avatar.url).to_s
URI::join(gitlab_config.url, avatar.url).to_s
else
GravatarService.new.execute(email, size)
end
......
......@@ -19,8 +19,6 @@ class UsersGroup < ActiveRecord::Base
Gitlab::Access.options_with_owner
end
attr_accessible :group_access, :user_id
belongs_to :user
belongs_to :group
......
......@@ -16,8 +16,6 @@ class UsersProject < ActiveRecord::Base
include Notifiable
include Gitlab::Access
attr_accessible :user, :user_id, :project_access
belongs_to :user
belongs_to :project
......@@ -126,7 +124,7 @@ class UsersProject < ActiveRecord::Base
author_id: self.user.id
)
notification_service.new_team_member(self)
notification_service.new_team_member(self) unless owner?
system_hook_service.execute_hooks_for(self, :create)
end
......
......@@ -22,8 +22,6 @@ class WebHook < ActiveRecord::Base
default_value_for :issues_events, false
default_value_for :merge_requests_events, false
attr_accessible :url
# HTTParty timeout
default_timeout 10
......
......@@ -25,7 +25,10 @@ module Files
file_path = path
unless file_name =~ Gitlab::Regex.path_regex
return error("Your changes could not be committed, because file name contains not allowed characters")
return error(
'Your changes could not be committed, because the file name ' +
Gitlab::Regex.path_regex_message
)
end
blob = repository.blob_at_branch(ref, file_path)
......
......@@ -4,6 +4,7 @@ module Issues
if issue.reopen
event_service.reopen_issue(issue, current_user)
create_note(issue)
notification_service.reopen_issue(issue, current_user)
execute_hooks(issue, 'reopen')
end
......
module Issues
class UpdateService < Issues::BaseService
def execute(issue)
state = params.delete('state_event') || params.delete(:state_event)
state = params[:state_event]
case state
when 'reopen'
......@@ -10,7 +10,7 @@ module Issues
Issues::CloseService.new(project, current_user, {}).execute(issue)
end
if params.present? && issue.update_attributes(params)
if params.present? && issue.update_attributes(params.except(:state_event))
issue.reset_events_cache
if issue.previous_changes.include?('milestone_id')
......
......@@ -6,7 +6,7 @@ module MergeRequests
# Called when you do merge via GitLab UI
class AutoMergeService < BaseMergeService
def execute(merge_request, current_user, commit_message)
merge_request.lock
merge_request.lock_mr
if Gitlab::Satellite::MergeAction.new(current_user, merge_request).merge!(commit_message)
merge_request.merge
......@@ -17,11 +17,11 @@ module MergeRequests
true
else
merge_request.unlock
merge_request.unlock_mr
false
end
rescue
merge_request.unlock if merge_request.locked?
merge_request.unlock_mr if merge_request.locked?
merge_request.mark_as_unmergeable
false
end
......
......@@ -3,6 +3,7 @@ module MergeRequests
def execute(merge_request)
if merge_request.reopen
event_service.reopen_mr(merge_request, current_user)
notification_service.reopen_mr(merge_request, current_user)
create_note(merge_request)
execute_hooks(merge_request)
merge_request.reload_code
......
......@@ -7,10 +7,10 @@ module MergeRequests
def execute(merge_request)
# We dont allow change of source/target projects
# after merge request was created
params.delete(:source_project_id)
params.delete(:target_project_id)
params.except!(:source_project_id)
params.except!(:target_project_id)
state = params.delete('state_event') || params.delete(:state_event)
state = params[:state_event]
case state
when 'reopen'
......@@ -19,7 +19,7 @@ module MergeRequests
MergeRequests::CloseService.new(project, current_user, {}).execute(merge_request)
end
if params.present? && merge_request.update_attributes(params)
if params.present? && merge_request.update_attributes(params.except(:state_event))
merge_request.reset_events_cache
if merge_request.previous_changes.include?('milestone_id')
......
module Milestones
class GroupService < Milestones::BaseService
def initialize(project_milestones)
@project_milestones = project_milestones.group_by(&:title)
end
def execute
build(@project_milestones)
end
def milestone(title)
if title
group_milestone = @project_milestones[title].group_by(&:title)
build(group_milestone).first
else
nil
end
end
private
def build(milestone)
milestone.map{ |title, milestones| GroupMilestone.new(title, milestones) }
end
end
end
module Milestones
class UpdateService < Milestones::BaseService
def execute(milestone)
state = params.delete('state_event') || params.delete(:state_event)
state = params[:state_event]
case state
when 'activate'
......@@ -11,7 +11,7 @@ module Milestones
end
if params.present?
milestone.update_attributes(params)
milestone.update_attributes(params.except(:state_event))
end
milestone
......
......@@ -80,6 +80,10 @@ class NotificationService
close_resource_email(merge_request, merge_request.target_project, current_user, 'closed_merge_request_email')
end
def reopen_issue(issue, current_user)
reopen_resource_email(issue, issue.project, current_user, 'issue_status_changed_email', 'reopened')
end
# When we merge a merge request we should send next emails:
#
# * merge_request author if their notification level is not Disabled
......@@ -89,12 +93,17 @@ class NotificationService
def merge_mr(merge_request, current_user)
recipients = reject_muted_users([merge_request.author, merge_request.assignee], merge_request.target_project)
recipients = recipients.concat(project_watchers(merge_request.target_project)).uniq
recipients.delete(current_user)
recipients.each do |recipient|
mailer.merged_merge_request_email(recipient.id, merge_request.id, current_user.id)
end
end
def reopen_mr(merge_request, current_user)
reopen_resource_email(merge_request, merge_request.target_project, current_user, 'merge_request_status_email', 'reopened')
end
# Notify new user with email after creation
def new_user(user)
# Don't email omniauth created users
......@@ -301,7 +310,9 @@ class NotificationService
end
def reassign_resource_email(target, project, current_user, method)
recipients = User.where(id: [target.assignee_id, target.assignee_id_was])
assignee_id_was = previous_record(target, "assignee_id")
recipients = User.where(id: [target.assignee_id, assignee_id_was])
# Add watchers to email list
recipients = recipients.concat(project_watchers(project))
......@@ -313,11 +324,29 @@ class NotificationService
recipients.delete(current_user)
recipients.each do |recipient|
mailer.send(method, recipient.id, target.id, target.assignee_id_was, current_user.id)
mailer.send(method, recipient.id, target.id, assignee_id_was, current_user.id)
end
end
def reopen_resource_email(target, project, current_user, method, status)
recipients = reject_muted_users([target.author, target.assignee], project)
recipients = recipients.concat(project_watchers(project)).uniq
recipients.delete(current_user)
recipients.each do |recipient|
mailer.send(method, recipient.id, target.id, status, current_user.id)
end
end
def mailer
Notify.delay
end
def previous_record(object, attribute)
if object && attribute
if object.previous_changes.include?(attribute)
object.previous_changes[attribute].first
end
end
end
end
......@@ -5,27 +5,13 @@ module Projects
end
def execute
# get namespace id
namespace_id = params.delete(:namespace_id)
@project = Project.new(params)
# check that user is allowed to set specified visibility_level
# Reset visibility levet if is not allowed to set it
unless Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level])
params.delete(:visibility_level)
@project.visibility_level = default_features.visibility_level
end
# Load default feature settings
default_features = Gitlab.config.gitlab.default_projects_features
default_opts = {
issues_enabled: default_features.issues,
wiki_enabled: default_features.wiki,
snippets_enabled: default_features.snippets,
merge_requests_enabled: default_features.merge_requests,
visibility_level: default_features.visibility_level
}.stringify_keys
@project = Project.new(default_opts.merge(params))
# Parametrize path for project
#
# Ex.
......@@ -33,13 +19,14 @@ module Projects
#
@project.path = @project.name.dup.parameterize unless @project.path.present?
# get namespace id
namespace_id = params[:namespace_id]
if namespace_id
# 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
else
unless allowed_namespace?(current_user, namespace_id)
@project.namespace_id = nil
deny_namespace
return @project
end
......
......@@ -12,7 +12,7 @@ module Projects
class TransferError < StandardError; end
def execute
namespace_id = params.delete(:namespace_id)
namespace_id = params[:namespace_id]
namespace = Namespace.find_by(id: namespace_id)
if allowed_transfer?(current_user, project, namespace)
......
module Projects
class UpdateService < BaseService
def execute(role = :default)
params[:project].delete(:namespace_id)
def execute
# check that user is allowed to set specified visibility_level
unless can?(current_user, :change_visibility_level, project) && Gitlab::VisibilityLevel.allowed_for?(current_user, params[:project][:visibility_level])
params[:project].delete(:visibility_level)
unless can?(current_user, :change_visibility_level, project) && Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level])
params[:visibility_level] = project.visibility_level
end
new_branch = params[:project].delete(:default_branch)
new_branch = params[:default_branch]
if project.repository.exists? && new_branch && new_branch != project.default_branch
project.change_head(new_branch)
end
if project.update_attributes(params[:project], as: role)
if project.previous_changes.include?('namespace_id')
project.send_move_instructions
end
if project.update_attributes(params.except(:default_branch))
if project.previous_changes.include?('path')
project.rename_repo
end
......
%h3.page-title
Issues
%span.pull-right #{@issues.total_count} issues
%p.light
List all issues from all projects you have access to.
......
%h3.page-title
Merge Requests
%span.pull-right #{@merge_requests.total_count} merge requests
%p.light
......
......@@ -6,4 +6,4 @@
<p>You can confirm your account through the link below:</p>
<% end %>
<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @resource.confirmation_token) %></p>
<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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