GitLab wurde aktualisiert. Dank regelmäßiger Updates bleibt das THM GitLab sicher und Sie profitieren von den neuesten Funktionen. Vielen Dank für Ihre Geduld.

Commit 78da7b1c authored by Robert Schilling's avatar Robert Schilling
Browse files

Merge branch 'master' of github.com:gitlabhq/gitlabhq

parents 5f3eef6e 747232ee
......@@ -2,8 +2,10 @@ Please view this file on the master branch, on stable branches it's out of date.
v 7.11.0 (unreleased)
- Make Reply-To config apply to change e-mail confirmation and other Devise notifications (Stan Hu)
- Add application setting to restrict user signups to e-mail domains (Stan Hu)
- Don't allow a merge request to be merged when its title starts with "WIP".
- Add a page title to every page.
- Allow primary email to be set to an email that you've already added.
- Get Gitorious importer to work again.
- Fix clone URL field and X11 Primary selection (Dmitry Medvinsky)
- Ignore invalid lines in .gitmodules
......@@ -23,6 +25,8 @@ v 7.11.0 (unreleased)
- Don't crash when an MR from a fork has a cross-reference comment from the target project on of its commits.
- Include commit comments in MR from a forked project.
- Fix adding new group members from admin area
- Group milestones by title in the dashboard and all other issue views.
- Query issues, merge requests and milestones with their IID through API (Julien Bianchi)
- Add default project and snippet visibility settings to the admin web UI.
- Show incompatible projects in Google Code import status (Stan Hu)
- Fix bug where commit data would not appear in some subdirectories (Stan Hu)
......@@ -30,6 +34,7 @@ v 7.11.0 (unreleased)
- Move snippets UI to fluid layout
- Improve UI for sidebar. Increase separation between navigation and content
- Improve new project command options (Ben Bodenmiller)
- Add common method to force UTF-8 and use it to properly handle non-ascii OAuth user properties (Onur Küçük)
- Prevent sending empty messages to HipChat (Chulki Lee)
- Improve UI for mobile phones on dashboard and project pages
- Add room notification and message color option for HipChat
......
......@@ -41,7 +41,8 @@ def application_setting_params
:max_attachment_size,
:default_project_visibility,
:default_snippet_visibility,
restricted_visibility_levels: []
:restricted_signup_domains_raw,
restricted_visibility_levels: [],
)
end
end
......@@ -102,8 +102,7 @@ def remove_email
email = user.emails.find(params[:email_id])
email.destroy
user.set_notification_email
user.save if user.notification_email_changed?
user.update_secondary_emails!
respond_to do |format|
format.html { redirect_to :back, notice: "Successfully removed email." }
......
......@@ -287,40 +287,15 @@ def set_filters_params
@filter_params
end
def set_filter_values(collection)
assignee_id = @filter_params[:assignee_id]
author_id = @filter_params[:author_id]
milestone_id = @filter_params[:milestone_id]
@sort = @filter_params[:sort]
@assignees = User.where(id: collection.pluck(:assignee_id))
@authors = User.where(id: collection.pluck(:author_id))
@milestones = Milestone.where(id: collection.pluck(:milestone_id))
if assignee_id.present? && !assignee_id.to_i.zero?
@assignee = @assignees.find_by(id: assignee_id)
end
if author_id.present? && !author_id.to_i.zero?
@author = @authors.find_by(id: author_id)
end
if milestone_id.present? && !milestone_id.to_i.zero?
@milestone = @milestones.find_by(id: milestone_id)
end
end
def get_issues_collection
set_filters_params
issues = IssuesFinder.new.execute(current_user, @filter_params)
set_filter_values(issues)
issues
end
def get_merge_requests_collection
set_filters_params
merge_requests = MergeRequestsFinder.new.execute(current_user, @filter_params)
set_filter_values(merge_requests)
merge_requests
end
......
class Profiles::EmailsController < Profiles::ApplicationController
def index
@primary = current_user.email
@public_email = current_user.public_email
@emails = current_user.emails
end
def create
@email = current_user.emails.new(email_params)
flash[:alert] = @email.errors.full_messages.first unless @email.save
if @email.save
NotificationService.new.new_email(@email)
else
flash[:alert] = @email.errors.full_messages.first
end
redirect_to profile_emails_url
end
......@@ -17,9 +20,7 @@ def destroy
@email = current_user.emails.find(params[:id])
@email.destroy
current_user.set_notification_email
current_user.set_public_email
current_user.save if current_user.notification_email_changed? or current_user.public_email_changed?
current_user.update_secondary_emails!
respond_to do |format|
format.html { redirect_to profile_emails_url }
......
......@@ -113,8 +113,9 @@ def sort(items)
end
def by_milestone(items)
if params[:milestone_id].present?
items = items.where(milestone_id: (params[:milestone_id] == NONE ? nil : params[:milestone_id]))
if params[:milestone_title].present?
milestone_ids = (params[:milestone_title] == NONE ? nil : Milestone.where(title: params[:milestone_title]).pluck(:id))
items = items.where(milestone_id: milestone_ids)
end
items
......
......@@ -28,6 +28,7 @@ def projects_milestones_options
Milestone.where(project_id: @projects)
end.active
options_from_collection_for_select(milestones, 'id', 'title', params[:milestone_id])
grouped_milestones = Milestones::GroupService.new(milestones).execute
options_from_collection_for_select(grouped_milestones, 'title', 'title', params[:milestone_title])
end
end
......@@ -18,11 +18,13 @@
# restricted_visibility_levels :text
# max_attachment_size :integer default(10)
# default_project_visibility :integer
# default_snippet_visibility :integer
# restricted_signup_domains :text
#
class ApplicationSetting < ActiveRecord::Base
serialize :restricted_visibility_levels
serialize :restricted_signup_domains, Array
attr_accessor :restricted_signup_domains_raw
validates :home_page_url,
allow_blank: true,
......@@ -55,11 +57,29 @@ def self.create_from_defaults
restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
max_attachment_size: Settings.gitlab['max_attachment_size'],
default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level']
default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
restricted_signup_domains: Settings.gitlab['restricted_signup_domains']
)
end
def home_page_url_column_exist
ActiveRecord::Base.connection.column_exists?(:application_settings, :home_page_url)
end
def restricted_signup_domains_raw
self.restricted_signup_domains.join("\n") unless self.restricted_signup_domains.nil?
end
def restricted_signup_domains_raw=(values)
self.restricted_signup_domains = []
self.restricted_signup_domains = values.split(
/\s*[,;]\s* # comma or semicolon, optionally surrounded by whitespace
| # or
\s # any whitespace character
| # or
[\r\n] # any number of newline characters
/x)
self.restricted_signup_domains.reject! { |d| d.empty? }
end
end
......@@ -18,7 +18,6 @@ class Email < ActiveRecord::Base
validates :email, presence: true, email: { strict_mode: true }, uniqueness: true
validate :unique_email, if: ->(email) { email.email_changed? }
after_create :notify
before_validation :cleanup_email
def cleanup_email
......@@ -28,8 +27,4 @@ def cleanup_email
def unique_email
self.errors.add(:email, 'has already been taken') if User.exists?(email: self.email)
end
def notify
NotificationService.new.new_email(self)
end
end
......@@ -139,13 +139,16 @@ class User < ActiveRecord::Base
validate :avatar_type, if: ->(user) { user.avatar_changed? }
validate :unique_email, if: ->(user) { user.email_changed? }
validate :owns_notification_email, if: ->(user) { user.notification_email_changed? }
validate :owns_public_email, if: ->(user) { user.public_email_changed? }
validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
before_validation :generate_password, on: :create
before_validation :restricted_signup_domains, on: :create
before_validation :sanitize_attrs
before_validation :set_notification_email, if: ->(user) { user.email_changed? }
before_validation :set_public_email, if: ->(user) { user.public_email_changed? }
after_update :update_emails_with_primary_email, if: ->(user) { user.email_changed? }
before_save :ensure_authentication_token
after_save :ensure_namespace_correct
after_initialize :set_projects_limit
......@@ -276,13 +279,29 @@ def avatar_type
end
def unique_email
self.errors.add(:email, 'has already been taken') if Email.exists?(email: self.email)
if !self.emails.exists?(email: self.email) && Email.exists?(email: self.email)
self.errors.add(:email, 'has already been taken')
end
end
def owns_notification_email
self.errors.add(:notification_email, "is not an email you own") unless self.all_emails.include?(self.notification_email)
end
def owns_public_email
self.errors.add(:public_email, "is not an email you own") unless self.all_emails.include?(self.public_email)
end
def update_emails_with_primary_email
primary_email_record = self.emails.find_by(email: self.email)
if primary_email_record
primary_email_record.destroy
self.emails.create(email: self.email_was)
self.update_secondary_emails!
end
end
# Groups user has access to
def authorized_groups
@authorized_groups ||= begin
......@@ -448,10 +467,16 @@ def set_notification_email
def set_public_email
if self.public_email.blank? || !self.all_emails.include?(self.public_email)
self.public_email = ''
self.public_email = nil
end
end
def update_secondary_emails!
self.set_notification_email
self.set_public_email
self.save if self.notification_email_changed? || self.public_email_changed?
end
def set_projects_limit
connection_default_value_defined = new_record? && !projects_limit_changed?
return unless self.projects_limit.nil? || connection_default_value_defined
......@@ -611,4 +636,27 @@ def contributed_projects_ids
select(:project_id).
uniq.map(&:project_id)
end
def restricted_signup_domains
email_domains = current_application_settings.restricted_signup_domains
unless email_domains.blank?
match_found = email_domains.any? do |domain|
escaped = Regexp.escape(domain).gsub('\*','.*?')
regexp = Regexp.new "^#{escaped}$", Regexp::IGNORECASE
email_domain = Mail::Address.new(self.email).domain
email_domain =~ regexp
end
unless match_found
self.errors.add :email,
'is not whitelisted. ' +
'Email domains valid for registration are: ' +
email_domains.join(', ')
return false
end
end
true
end
end
......@@ -72,6 +72,11 @@
= f.label :max_attachment_size, 'Maximum attachment size (MB)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :max_attachment_size, class: 'form-control'
.form-group
= f.label :restricted_signup_domains, 'Restricted domains for sign-ups', class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :restricted_signup_domains_raw, placeholder: 'domain.com', class: 'form-control'
.help-block Ex: domain.com, *.domain.com. Wildcards allowed. Use separate lines for multiple entries.
.form-actions
= f.submit 'Save', class: 'btn btn-primary'
......@@ -5,11 +5,15 @@
Your
%b Primary Email
will be used for avatar detection and web based operations, such as edits and merges.
%br
%p.light
Your
%b Notification Email
will be used for account notifications.
%br
%p.light
Your
%b Public Email
will be displayed on your public profile.
%p.light
All email addresses will be used to identify your commits.
%hr
......@@ -21,13 +25,17 @@
%li
%strong= @primary
%span.label.label-success Primary Email
- if @primary === @public_email
- if @primary === current_user.public_email
%span.label.label-info Public Email
- if @primary === current_user.notification_email
%span.label.label-info Notification Email
- @emails.each do |email|
%li
%strong= email.email
- if email.email === @public_email
- if email.email === current_user.public_email
%span.label.label-info Public Email
- if email.email === current_user.notification_email
%span.label.label-info Notification Email
%span.cgray
added #{time_ago_with_tooltip(email.created_at)}
= link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-sm btn-remove pull-right'
......
......@@ -15,7 +15,7 @@
#{state_filters_text_for(:all, @project)}
.issues-details-filters
= form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_id, :label_name]), method: :get, class: 'filter-form' do
= form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name]), method: :get, class: 'filter-form' do
- if controller.controller_name == 'issues'
.check-all-holder
= check_box_tag "check_all_issues", nil, false,
......@@ -31,7 +31,7 @@
placeholder: 'Author', class: 'trigger-submit', any_user: true, first_user: true)
.filter-item.inline.milestone-filter
= select_tag('milestone_id', projects_milestones_options, class: "select2 trigger-submit", prompt: 'Milestone')
= select_tag('milestone_title', projects_milestones_options, class: "select2 trigger-submit", prompt: 'Milestone')
- if @project
.filter-item.inline.labels-filter
......
......@@ -132,6 +132,7 @@ def verify_constant(modul, current, default)
Settings.gitlab.default_projects_features['snippets'] = false if Settings.gitlab.default_projects_features['snippets'].nil?
Settings.gitlab.default_projects_features['visibility_level'] = Settings.send(:verify_constant, Gitlab::VisibilityLevel, Settings.gitlab.default_projects_features['visibility_level'], Gitlab::VisibilityLevel::PRIVATE)
Settings.gitlab['repository_downloads_path'] = File.absolute_path(Settings.gitlab['repository_downloads_path'] || 'tmp/repositories', Rails.root)
Settings.gitlab['restricted_signup_domains'] ||= []
#
# Gravatar
......
class AddRestrictedSignupDomainsToApplicationSettings < ActiveRecord::Migration
def change
add_column :application_settings, :restricted_signup_domains, :text
end
end
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20150429002313) do
ActiveRecord::Schema.define(version: 20150502064022) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -31,6 +31,7 @@
t.integer "max_attachment_size", default: 10, null: false
t.integer "default_project_visibility"
t.integer "default_snippet_visibility"
t.text "restricted_signup_domains"
end
create_table "broadcast_messages", force: true do |t|
......
......@@ -35,7 +35,7 @@ Parameters:
## New group
Creates a new project group. Available only for admin.
Creates a new project group. Available only for users who can create groups.
```
POST /groups
......
......@@ -99,11 +99,13 @@ GET /projects/:id/issues?labels=foo,bar
GET /projects/:id/issues?labels=foo,bar&state=opened
GET /projects/:id/issues?milestone=1.0.0
GET /projects/:id/issues?milestone=1.0.0&state=opened
GET /projects/:id/issues?iid=42
```
Parameters:
- `id` (required) - The ID of a project
- `iid` (optional) - Return the issue having the given `iid`
- `state` (optional) - Return `all` issues or just those that are `opened` or `closed`
- `labels` (optional) - Comma-separated list of label names
- `milestone` (optional) - Milestone title
......
......@@ -10,11 +10,13 @@ The pagination parameters `page` and `per_page` can be used to restrict the list
GET /projects/:id/merge_requests
GET /projects/:id/merge_requests?state=opened
GET /projects/:id/merge_requests?state=all
GET /projects/:id/merge_requests?iid=42
```
Parameters:
- `id` (required) - The ID of a project
- `iid` (optional) - Return the request having the given `iid`
- `state` (optional) - Return `all` requests or just those that are `merged`, `opened` or `closed`
- `order_by` (optional) - Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at`
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
......@@ -388,6 +390,6 @@ Parameters:
]
```
## Comments on issues
## Comments on merge requets
Comments are done via the notes resource.
......@@ -6,6 +6,7 @@ Returns a list of project milestones.
```
GET /projects/:id/milestones
GET /projects/:id/milestones?iid=42
```
```json
......@@ -27,6 +28,7 @@ GET /projects/:id/milestones
Parameters:
- `id` (required) - The ID of a project
- `iid` (optional) - Return the milestone having the given `iid`
## Get single milestone
......
......@@ -20,7 +20,7 @@ class Groups < Grape::API
present @groups, with: Entities::Group
end
# Create group. Available only for admin
# Create group. Available only for users who can create groups.
#
# Parameters:
# name (required) - The name of the group
......@@ -28,7 +28,7 @@ class Groups < Grape::API
# Example Request:
# POST /groups
post do
authenticated_as_admin!
authorize! :create_group, current_user
required_attributes! [:name, :path]
attrs = attributes_for_keys [:name, :path, :description]
......
......@@ -173,6 +173,10 @@ def issuable_sort
end
end
def filter_by_iid(items, iid)
items.where(iid: iid)
end
# error helpers
def forbidden!(reason = nil)
......
......@@ -51,6 +51,7 @@ def filter_issues_milestone(issues, milestone)
#
# Parameters:
# id (required) - The ID of a project
# iid (optional) - Return the project issue having the given `iid`
# state (optional) - Return "opened" or "closed" issues
# labels (optional) - Comma-separated list of label names
# milestone (optional) - Milestone title
......@@ -66,10 +67,12 @@ def filter_issues_milestone(issues, milestone)
# GET /projects/:id/issues?labels=foo,bar&state=opened
# GET /projects/:id/issues?milestone=1.0.0
# GET /projects/:id/issues?milestone=1.0.0&state=closed
# GET /issues?iid=42
get ":id/issues" do
issues = user_project.issues
issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
issues = filter_by_iid(issues, params[:iid]) unless params[:iid].nil?
unless params[:milestone].nil?
issues = filter_issues_milestone(issues, params[:milestone])
......
......@@ -24,6 +24,7 @@ def handle_merge_request_errors!(errors)
#
# Parameters:
# id (required) - The ID of a project
# iid (optional) - Return the project MR having the given `iid`
# state (optional) - Return requests "merged", "opened" or "closed"
# order_by (optional) - Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at`
# sort (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
......@@ -36,11 +37,16 @@ def handle_merge_request_errors!(errors)
# GET /projects/:id/merge_requests?order_by=updated_at
# GET /projects/:id/merge_requests?sort=desc
# GET /projects/:id/merge_requests?sort=asc
# GET /projects/:id/merge_requests?iid=42
#
get ":id/merge_requests" do
authorize! :read_merge_request, user_project
merge_requests = user_project.merge_requests
unless params[:iid].nil?
merge_requests = filter_by_iid(merge_requests, params[:iid])
end
merge_requests =
case params["state"]
when "opened" then merge_requests.opened
......@@ -169,8 +175,8 @@ def handle_merge_request_errors!(errors)
# Merge MR
#
# Parameters:
# id (required) - The ID of a project
# merge_request_id (required) - ID of MR
# id (required) - The ID of a project
# merge_request_id (required) - ID of MR
# merge_commit_message (optional) - Custom merge commit message
# Example:
# PUT /projects/:id/merge_request/:merge_request_id/merge
......@@ -209,7 +215,7 @@ def handle_merge_request_errors!(errors)
# Get a merge request's comments
#
# Parameters:
# id (required) - The ID of a project
# id (required) - The ID of a project
# merge_request_id (required) - ID of MR
# Examples:
# GET /projects/:id/merge_request/:merge_request_id/comments
......@@ -225,9 +231,9 @@ def handle_merge_request_errors!(errors)
# Post comment to merge request
#
# Parameters:
# id (required) - The ID of a project
# id (required) - The ID of a project
# merge_request_id (required) - ID of MR
# note (required) - Text of comment
# note (required) - Text of comment
# Examples:
# POST /projects/:id/merge_request/:merge_request_id/comments
#
......
......@@ -9,11 +9,11 @@ def initialize(auth_hash)
end
def uid
auth_hash.uid.to_s
Gitlab::Utils.force_utf8(auth_hash.uid.to_s)
end
def provider
auth_hash.provider
Gitlab::Utils.force_utf8(auth_hash.provider.to_s)
end
def info
......@@ -21,23 +21,28 @@ def info
end
def name
(info.try(:name) || full_name).to_s.force_encoding('utf-8')
Gitlab::Utils.force_utf8((info.try(:name) || full_name).to_s)
end
def full_name
"#{info.first_name} #{info.last_name}"
Gitlab::Utils.force_utf8("#{info.first_name} #{info.last_name}")
end
def username
(info.try(:nickname) || generate_username).to_s.force_encoding('utf-8')
Gitlab::Utils.force_utf8(
(info.try(:nickname) || generate_username).to_s
)
end
def email
(info.try(:email) || generate_temporarily_email).downcase
Gitlab::Utils.force_utf8(
(info.try(:email) || generate_temporarily_email).downcase
)