Commit f23ffeec authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch '6-5-dev'

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

Conflicts:
	VERSION
parents 59c5a42e 68118b54
No related merge requests found
v 6.5.0
- Dropdown menus on issue#show page for assignee and milestone (Jason Blanchard)
- Add color custimization and previewing to broadcast messages
v 6.4.0 v 6.4.0
- Added sorting to project issues page (Jason Blanchard) - Added sorting to project issues page (Jason Blanchard)
- Assembla integration (Carlos Paramio) - Assembla integration (Carlos Paramio)
......
6.4.0 6.5.0.pre
...@@ -8,6 +8,23 @@ class Admin ...@@ -8,6 +8,23 @@ class Admin
else else
elems.removeAttr 'disabled' elems.removeAttr 'disabled'
$('body').on 'click', '.js-toggle-colors-link', (e) ->
e.preventDefault()
$('.js-toggle-colors-link').hide()
$('.js-toggle-colors-container').show()
$('input#broadcast_message_color').on 'input', ->
previewColor = $('input#broadcast_message_color').val()
$('div.broadcast-message-preview').css('background-color', previewColor)
$('input#broadcast_message_font').on 'input', ->
previewColor = $('input#broadcast_message_font').val()
$('div.broadcast-message-preview').css('color', previewColor)
$('textarea#broadcast_message_message').on 'input', ->
previewMessage = $('textarea#broadcast_message_message').val()
$('div.broadcast-message-preview span').text(previewMessage)
$('.log-tabs a').click (e) -> $('.log-tabs a').click (e) ->
e.preventDefault() e.preventDefault()
$(this).tab('show') $(this).tab('show')
......
...@@ -79,3 +79,9 @@ ...@@ -79,3 +79,9 @@
$("#update_issues_ids").val [] $("#update_issues_ids").val []
$(".issues_bulk_update").hide() $(".issues_bulk_update").hide()
$(".issues-filters").show() $(".issues-filters").show()
$ ->
$('.edit-issue.inline-update input[type="submit"]').hide();
$("body").on "change", ".edit-issue.inline-update select", ->
$(this).submit()
...@@ -361,6 +361,11 @@ table { ...@@ -361,6 +361,11 @@ table {
color: #BBB; color: #BBB;
} }
.broadcast-message-preview {
@extend .broadcast-message;
margin-bottom: 20px;
}
.ajax-users-select { .ajax-users-select {
width: 400px; width: 400px;
......
...@@ -106,13 +106,11 @@ pre.well-pre { ...@@ -106,13 +106,11 @@ pre.well-pre {
/** Big Labels **/ /** Big Labels **/
.state-label { .state-label {
font-size: 14px; font-size: 14px;
padding: 5px 15px; padding: 6px 25px;
text-align: center; text-align: center;
float: right;
position: relative;
top: -5px;
@include border-radius(4px); @include border-radius(4px);
text-shadow: none; text-shadow: none;
margin-left: 10px;
&.state-label-green { &.state-label-green {
background: #4A4; background: #4A4;
......
...@@ -119,3 +119,16 @@ input.check_all_issues { ...@@ -119,3 +119,16 @@ input.check_all_issues {
background-color: #f4f4f4; background-color: #f4f4f4;
} }
} }
.edit-issue.inline-update select {
width: 100%;
max-width: 200px;
}
.issue-show-labels .label {
padding: 6px 10px;
}
form.edit-issue {
margin: 0;
}
...@@ -51,3 +51,7 @@ ...@@ -51,3 +51,7 @@
.chosen-container .chosen-drop .chosen-search input { .chosen-container .chosen-drop .chosen-search input {
background-position-y: -24px !important; background-position-y: -24px !important;
} }
.chosen-compact {
max-width: 170px !important;
}
module BroadcastMessagesHelper
def broadcast_styling(broadcast_message)
if(broadcast_message.color || broadcast_message.font)
"background-color:#{broadcast_message.color};color:#{broadcast_message.font}"
else
""
end
end
end
...@@ -76,4 +76,12 @@ module IssuesHelper ...@@ -76,4 +76,12 @@ module IssuesHelper
def bulk_update_assignee_options def bulk_update_assignee_options
options_for_select(["None (unassigned)", nil]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id]) options_for_select(["None (unassigned)", nil]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id])
end end
def assignee_options object
options_from_collection_for_select(@project.team.members.sort_by(&:name), 'id', 'name', object.assignee_id)
end
def milestone_options object
options_from_collection_for_select(@project.milestones.active, 'id', 'title', object.milestone_id)
end
end end
...@@ -9,15 +9,20 @@ ...@@ -9,15 +9,20 @@
# alert_type :integer # alert_type :integer
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# color :string(255)
# font :string(255)
# #
class BroadcastMessage < ActiveRecord::Base class BroadcastMessage < ActiveRecord::Base
attr_accessible :alert_type, :ends_at, :message, :starts_at attr_accessible :alert_type, :color, :ends_at, :font, :message, :starts_at
validates :message, presence: true validates :message, presence: true
validates :starts_at, presence: true validates :starts_at, presence: true
validates :ends_at, presence: true validates :ends_at, presence: true
validates :color, format: { with: /\A\#[0-9A-Fa-f]{6}+\Z/ }, allow_blank: true
validates :font, format: { with: /\A\#[0-9A-Fa-f]{6}+\Z/ }, allow_blank: true
def self.current def self.current
where("ends_at > :now AND starts_at < :now", now: Time.zone.now).last where("ends_at > :now AND starts_at < :now", now: Time.zone.now).last
end end
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
Broadcast Messages Broadcast Messages
%p.light %p.light
Broadcast messages are displayed for every user and can be used to notify users about scheduled maintenance, recent upgrades and more. Broadcast messages are displayed for every user and can be used to notify users about scheduled maintenance, recent upgrades and more.
%hr .broadcast-message-preview
%i.icon-bullhorn
%span Your message here
= form_for [:admin, @broadcast_message] do |f| = form_for [:admin, @broadcast_message] do |f|
-if @broadcast_message.errors.any? -if @broadcast_message.errors.any?
...@@ -13,6 +15,19 @@ ...@@ -13,6 +15,19 @@
= f.label :message = f.label :message
.controls .controls
= f.text_area :message, class: "input-xxlarge", rows: 2, required: true = f.text_area :message, class: "input-xxlarge", rows: 2, required: true
%div
= link_to '#', class: 'js-toggle-colors-link' do
Customize colors
.control-group.js-toggle-colors-container.hide
= f.label :color, "Background Color"
.controls
= f.text_field :color, placeholder: "#AA33EE"
.light Hex values as 3 double digit numbers, starting with a # sign.
.control-group.js-toggle-colors-container.hide
= f.label :font, "Font Color"
.controls
= f.text_field :font, placeholder: "#224466"
.light Hex values as 3 double digit numbers, starting with a # sign.
.control-group .control-group
= f.label :starts_at = f.label :starts_at
.controls.datetime-controls .controls.datetime-controls
......
- if broadcast_message.present? - if broadcast_message.present?
.broadcast-message .broadcast-message{ style: broadcast_styling(broadcast_message) }
%i.icon-bullhorn %i.icon-bullhorn
= broadcast_message.message = broadcast_message.message
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
Assign to Assign to
.controls .controls
.pull-left .pull-left
= f.select(:assignee_id, @project.team.members.sort_by(&:name).map {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }, {class: 'chosen'}) = f.select(:assignee_id, assignee_options(@issue), { include_blank: "Select a user" }, {class: 'chosen'})
.pull-right .pull-right
&nbsp; &nbsp;
= link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link' = link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link'
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
= f.label :milestone_id do = f.label :milestone_id do
%i.icon-time %i.icon-time
Milestone Milestone
.controls= f.select(:milestone_id, @project.milestones.active.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'}) .controls= f.select(:milestone_id, milestone_options(@issue), { include_blank: "Select milestone" }, {class: 'chosen'})
.ui-box-bottom .ui-box-bottom
.control-group .control-group
......
= form_for [@project, @issue], remote: true, html: {class: 'edit-issue inline-update'} do |f|
.pull-right
Created by #{link_to_member(@project, issue.author)}&nbsp;
- if issue.assignee
\ and currently assigned to
- if can?(current_user, :modify_issue, @issue)
= link_to profile_path(issue.assignee) do
= image_tag(avatar_icon(issue.assignee.email), class: 'avatar avatar-inline s16 assignee') if issue.assignee
= f.select(:assignee_id, assignee_options(@issue), { include_blank: "Assign to user (none):" }, {class: 'chosen'})
- elsif issue.assignee
= link_to_member(@project, @issue.assignee)
.pull-right
- if issue.milestone
- milestone = issue.milestone
%cite.cgray Attached to milestone
- if can?(current_user, :modify_issue, @issue)
= f.select(:milestone_id, milestone_options(@issue), { include_blank: "Select milestone (none):" }, {class: 'chosen chosen-compact'})
= hidden_field_tag :issue_context
= f.submit class: 'btn'
- elsif issue.milestone
= link_to issue.milestone.title, project_milestone_path
...@@ -2,8 +2,12 @@ ...@@ -2,8 +2,12 @@
Issue ##{@issue.iid} Issue ##{@issue.iid}
%small %small
created at created #{time_ago_with_tooltip(@issue.created_at)} ago
= @issue.created_at.stamp("Aug 21, 2011")
- if @issue.closed?
%span.state-label.state-label-red Closed
- else
%span.state-label.state-label-green Open
%span.pull-right %span.pull-right
- if can?(current_user, :write_issue, @project) - if can?(current_user, :write_issue, @project)
...@@ -26,34 +30,21 @@ ...@@ -26,34 +30,21 @@
.back-link .back-link
= link_to project_issues_path(@project) do = link_to project_issues_path(@project) do
&larr; To issues list &larr; To issues list
%span.milestone-nav-link
- if @issue.milestone
|
= link_to project_milestone_path(@project, @issue.milestone) do
%span.light Milestone
= @issue.milestone.title
.ui-box.ui-box-show .ui-box.ui-box-show
.ui-box-head .ui-box-head
%h4.box-title %h4.box-title
- if @issue.closed?
.state-label.state-label-red Closed
- else
.state-label.state-label-green Open
= gfm escape_once(@issue.title) = gfm escape_once(@issue.title)
.ui-box-body .ui-box-body
%cite.cgray %cite.cgray
Created by #{link_to_member(@project, @issue.author)} = render partial: 'issue_context', locals: { issue: @issue }
- if @issue.assignee
\ and currently assigned to #{link_to_member(@project, @issue.assignee)}
- if @issue.milestone
- milestone = @issue.milestone
%cite.cgray and attached to milestone
%strong= link_to_gfm truncate(milestone.title, length: 20), project_milestone_path(milestone.project, milestone)
.pull-right
- @issue.labels.each do |label|
%span{class: "label #{label_css_class(label.name)}"}
%i.icon-tag
= label.name
&nbsp;
- if @issue.description.present? - if @issue.description.present?
.ui-box-bottom .ui-box-bottom
...@@ -73,4 +64,11 @@ ...@@ -73,4 +64,11 @@
- @issue.participants.each do |participant| - @issue.participants.each do |participant|
= link_to_member(@project, participant, name: false, size: 24) = link_to_member(@project, participant, name: false, size: 24)
.voting_notes#notes= render "projects/notes/notes_with_form" .issue-show-labels.pull-right
\ No newline at end of file - @issue.labels.each do |label|
%span{class: "label #{label_css_class(label.name)}"}
%i.icon-tag
= label.name
&nbsp;
.voting_notes#notes= render "projects/notes/notes_with_form"
...@@ -2,3 +2,12 @@ ...@@ -2,3 +2,12 @@
- if @issue.valid? - if @issue.valid?
:plain :plain
$("##{dom_id(@issue)}").fadeOut(); $("##{dom_id(@issue)}").fadeOut();
- elsif params[:issue_context]
$('.ui-box-body').html("#{escape_javascript(render partial: 'issue_context', locals: { issue: @issue })}");
$('.ui-box-body').effect('highlight');
$('.chosen').chosen();
$('.edit-issue.inline-update input[type="submit"]').hide();
- if @issue.milestone
$('.milestone-nav-link').replaceWith("#{escape_javascript(link_to "| #{@issue.milestone.title}", project_milestone_path(@issue.project, @issue.milestone), :class => 'milestone-nav-link')}")
- else
$('.milestone-nav-link').html('')
...@@ -39,12 +39,12 @@ ...@@ -39,12 +39,12 @@
= f.label :assignee_id do = f.label :assignee_id do
%i.icon-user %i.icon-user
Assign to Assign to
.controls= f.select(:assignee_id, @project.team.members.sort_by(&:name).map {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'}) .controls= f.select(:assignee_id, assignee_options(@merge_request), { include_blank: "Select user" }, {class: 'chosen span3'})
.left .left
= f.label :milestone_id do = f.label :milestone_id do
%i.icon-time %i.icon-time
Milestone Milestone
.controls= f.select(:milestone_id, @project.milestones.active.map {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'}) .controls= f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone" }, {class: 'chosen'})
.control-group .control-group
= f.label :description, "Description" = f.label :description, "Description"
.controls .controls
......
...@@ -2,25 +2,18 @@ ...@@ -2,25 +2,18 @@
.ui-box-head .ui-box-head
%h4.box-title %h4.box-title
= gfm escape_once(@merge_request.title) = gfm escape_once(@merge_request.title)
- if @merge_request.merged?
.state-label.state-label-green
%i.icon-ok
Merged
- elsif @merge_request.closed?
.state-label.state-label-red
Closed
.ui-box-body .ui-box-body
%div %div
%cite.cgray %cite.cgray
Created on #{@merge_request.created_at.stamp("Aug 21, 2011")} by #{link_to_member(@project, @merge_request.author)}. Created by #{link_to_member(@project, @merge_request.author)}.
- if @merge_request.assignee - if @merge_request.assignee
Currently assigned to #{link_to_member(@project, @merge_request.assignee)}. Currently assigned to #{link_to_member(@project, @merge_request.assignee)}.
- if @merge_request.milestone - if @merge_request.milestone
- milestone = @merge_request.milestone .pull-right
%cite.cgray Attached to milestone - milestone = @merge_request.milestone
%strong= link_to_gfm truncate(milestone.title, length: 20), project_milestone_path(milestone.project, milestone) %cite.cgray Attached to milestone
\. %strong= link_to_gfm truncate(milestone.title, length: 20), project_milestone_path(milestone.project, milestone)
- if @merge_request.description.present? - if @merge_request.description.present?
......
%h3.page-title %h3.page-title
= "Merge Request ##{@merge_request.iid}:" = "Merge Request ##{@merge_request.iid}"
&nbsp; %small
-if @merge_request.for_fork? created #{time_ago_with_tooltip(@merge_request.created_at)} ago
%span.label-branch
%span.label-project= truncate(@merge_request.source_project_path, length: 25) - if @merge_request.merged?
#{@merge_request.source_branch} %span.state-label.state-label-green
&rarr; %i.icon-ok
%span.label-branch= @merge_request.target_branch Merged
- elsif @merge_request.closed?
%span.state-label.state-label-red
Closed
- else - else
%span.label-branch= @merge_request.source_branch %span.state-label.state-label-green
&rarr; Open
%span.label-branch= @merge_request.target_branch
%span.pull-right %span.pull-right
- if can?(current_user, :modify_merge_request, @merge_request) - if can?(current_user, :modify_merge_request, @merge_request)
...@@ -36,3 +40,16 @@ ...@@ -36,3 +40,16 @@
.back-link .back-link
= link_to project_merge_requests_path(@project) do = link_to project_merge_requests_path(@project) do
&larr; To merge requests &larr; To merge requests
%span.prepend-left-20.monospace
-if @merge_request.for_fork?
%span
%strong
#{truncate(@merge_request.source_project_path, length: 25)}:
#{@merge_request.source_branch}
&rarr;
%span= @merge_request.target_branch
- else
%span= @merge_request.source_branch
&rarr;
%spanh= @merge_request.target_branch
...@@ -3,15 +3,21 @@ ...@@ -3,15 +3,21 @@
Milestone ##{@milestone.iid} Milestone ##{@milestone.iid}
%small %small
= @milestone.expires_at = @milestone.expires_at
- if @milestone.closed?
%span.state-label.state-label-red Closed
- elsif @milestone.expired?
%span.state-label.state-label-red Expired
- else
%span.state-label.state-label-green Open
.pull-right .pull-right
- if can?(current_user, :admin_milestone, @project) - if can?(current_user, :admin_milestone, @project)
= link_to edit_project_milestone_path(@project, @milestone), class: "btn grouped" do = link_to edit_project_milestone_path(@project, @milestone), class: "btn grouped" do
%i.icon-edit %i.icon-edit
Edit Edit
- if @milestone.active? - if @milestone.active?
= link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-remove" = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-remove grouped"
- else - else
= link_to 'Reopen Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn" = link_to 'Reopen Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn grouped"
- if @milestone.issues.any? && @milestone.can_be_closed? - if @milestone.issues.any? && @milestone.can_be_closed?
.alert.alert-success .alert.alert-success
...@@ -25,10 +31,6 @@ ...@@ -25,10 +31,6 @@
.ui-box.ui-box-show .ui-box.ui-box-show
.ui-box-head .ui-box-head
%h4.box-title %h4.box-title
- if @milestone.closed?
.state-label.state-label-red Closed
- elsif @milestone.expired?
.state-label.state-label-red Expired
= gfm escape_once(@milestone.title) = gfm escape_once(@milestone.title)
......
class AddColorAndFontToBroadcastMessages < ActiveRecord::Migration
def change
add_column :broadcast_messages, :color, :string
add_column :broadcast_messages, :font, :string
end
end
...@@ -20,6 +20,8 @@ ActiveRecord::Schema.define(version: 20131217102743) do ...@@ -20,6 +20,8 @@ ActiveRecord::Schema.define(version: 20131217102743) do
t.integer "alert_type" t.integer "alert_type"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.string "color"
t.string "font"
end end
create_table "deploy_keys_projects", force: true do |t| create_table "deploy_keys_projects", force: true do |t|
......
...@@ -11,3 +11,10 @@ Feature: Admin Broadcast Messages ...@@ -11,3 +11,10 @@ Feature: Admin Broadcast Messages
When submit form with new broadcast message When submit form with new broadcast message
Then I should be redirected to admin messages page Then I should be redirected to admin messages page
And I should see newly created broadcast message And I should see newly created broadcast message
Scenario: Create a customized broadcast message
When submit form with new customized broadcast message
Then I should be redirected to admin messages page
And I should see newly created broadcast message
Then I visit dashboard page
And I should see a customized broadcast message
...@@ -24,4 +24,18 @@ class Spinach::Features::AdminBroadcastMessages < Spinach::FeatureSteps ...@@ -24,4 +24,18 @@ class Spinach::Features::AdminBroadcastMessages < Spinach::FeatureSteps
step 'I should see newly created broadcast message' do step 'I should see newly created broadcast message' do
page.should have_content 'Application update from 4:00 CST to 5:00 CST' page.should have_content 'Application update from 4:00 CST to 5:00 CST'
end end
step 'submit form with new customized broadcast message' do
fill_in 'broadcast_message_message', with: 'Application update from 4:00 CST to 5:00 CST'
click_link "Customize colors"
fill_in 'broadcast_message_color', with: '#f2dede'
fill_in 'broadcast_message_font', with: '#b94a48'
select '2018', from: "broadcast_message_ends_at_1i"
click_button "Add broadcast message"
end
step 'I should see a customized broadcast message' do
page.should have_content 'Application update from 4:00 CST to 5:00 CST'
page.should have_selector %(div[style="background-color:#f2dede;color:#b94a48"])
end
end end
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
# alert_type :integer # alert_type :integer
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# color :string(255)
# font :string(255)
# #
# Read about factories at https://github.com/thoughtbot/factory_girl # Read about factories at https://github.com/thoughtbot/factory_girl
...@@ -19,5 +21,7 @@ FactoryGirl.define do ...@@ -19,5 +21,7 @@ FactoryGirl.define do
starts_at "2013-11-12 13:43:25" starts_at "2013-11-12 13:43:25"
ends_at "2013-11-12 13:43:25" ends_at "2013-11-12 13:43:25"
alert_type 1 alert_type 1
color "#555555"
font "#BBBBBB"
end end
end end
...@@ -175,6 +175,84 @@ describe "Issues" do ...@@ -175,6 +175,84 @@ describe "Issues" do
end end
end end
describe 'update assignee from issue#show' do
let(:issue) { create(:issue, project: project, author: @user) }
context 'by autorized user' do
it 'with dropdown menu' do
visit project_issue_path(project, issue)
find('.edit-issue.inline-update').select(project.team.members.first.name, from: 'issue_assignee_id')
click_button 'Update Issue'
page.should have_content "currently assigned to"
page.has_select?('issue_assignee_id', :selected => project.team.members.first.name)
end
end
context 'by unauthorized user' do
let(:guest) { create(:user) }
before :each do
project.team << [[guest], :guest]
issue.assignee = @user
issue.save
end
it 'shows assignee text' do
logout
login_with guest
visit project_issue_path(project, issue)
page.should have_content "currently assigned to #{issue.assignee.name}"
end
end
end
describe 'update milestone from issue#show' do
let!(:issue) { create(:issue, project: project, author: @user) }
let!(:milestone) { create(:milestone, project: project) }
context 'by authorized user' do
it 'with dropdown menu' do
visit project_issue_path(project, issue)
p find('.edit-issue.inline-update').text
find('.edit-issue.inline-update').select(milestone.title, from: 'issue_milestone_id')
click_button 'Update Issue'
page.should have_content "Attached to milestone"
page.has_select?('issue_assignee_id', :selected => milestone.title)
end
end
context 'by unauthorized user' do
let(:guest) { create(:user) }
before :each do
project.team << [[guest], :guest]
issue.milestone = milestone
issue.save
end
it 'shows milestone text' do
logout
login_with guest
visit project_issue_path(project, issue)
page.should have_content "Attached to milestone #{milestone.title}"
end
end
end
def first_issue def first_issue
all("ul.issues-list li").first.text all("ul.issues-list li").first.text
end end
......
require 'spec_helper'
describe BroadcastMessagesHelper do
describe 'broadcast_styling' do
let(:broadcast_message) { double(color: "", font: "") }
context "default style" do
it "should have no style" do
broadcast_styling(broadcast_message).should match('')
end
end
context "customiezd style" do
before { broadcast_message.stub(color: "#f2dede", font: "#b94a48") }
it "should have a customized style" do
broadcast_styling(broadcast_message).should match('background-color:#f2dede;color:#b94a48')
end
end
end
end
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
# alert_type :integer # alert_type :integer
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# color :string(255)
# font :string(255)
# #
require 'spec_helper' require 'spec_helper'
......
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