diff --git a/.gitignore b/.gitignore
index 760487ca..d22760e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,4 +22,4 @@ config/unicorn.rb
db/data.yml
.idea
.DS_Store
-
+.chef
diff --git a/.travis.yml b/.travis.yml
index da67e37d..bb4c4a79 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,6 +9,8 @@ branches:
- 'master'
rvm:
- 1.9.3
+services:
+ - mysql
before_script:
- "cp config/database.yml.$DB config/database.yml"
- "cp config/gitlab.yml.example config/gitlab.yml"
diff --git a/CHANGELOG b/CHANGELOG
index 6868c07b..99641ad3 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,19 @@
+v 2.9.0
+ - fixed inline notes bugs
+ - refactored rspecs
+ - refactored gitolite backend
+ - added factory_girl
+ - restyled projects list on dashboard
+ - ssh keys validation to prevent gitolite crash
+ - send notifications if changed premission in project
+ - scss refactoring. gitlab_bootstrap/ dir
+ - fix git push http body bigger than 112k problem
+ - list of labels page under issues tab
+ - API for milestones, keys
+ - restyled buttons
+ - OAuth
+ - Comment order changed
+
v 2.8.1
- ability to disable gravatars
- improved MR diff logic
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..9041530d
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,30 @@
+## Contribute to GitLab
+
+If you want to contribute to GitLab, follow this process:
+
+1. Fork the project
+2. Create a feature branch
+3. Code
+4. Create a pull request
+
+We only accept pull requests if:
+
+* Your code has proper tests and all tests pass
+* Your code can be merged w/o problems
+* It wont broke existing functionality
+* Its a quality code
+* We like it :)
+
+## [You may need a developer VM](https://github.com/gitlabhq/developer-vm)
+
+## Running tests
+
+To run the specs for GitLab, you need to run seeds for test db.
+
+ cd gitlabhq
+ rake db:seed_fu RAILS_ENV=test
+
+Then you can run the test suite with rake:
+
+ rake gitlab:test
+
diff --git a/Gemfile b/Gemfile
index 045baa36..8e569c5b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,5 +1,13 @@
source "http://rubygems.org"
+def darwin_only(require_as)
+ RUBY_PLATFORM.include?('darwin') && require_as
+end
+
+def linux_only(require_as)
+ RUBY_PLATFORM.include?('linux') && require_as
+end
+
gem "rails", "3.2.8"
# Supported DBs
@@ -8,6 +16,10 @@ gem "mysql2"
# Auth
gem "devise", "~> 2.1.0"
+gem 'omniauth'
+gem 'omniauth-google-oauth2'
+gem 'omniauth-twitter'
+gem 'omniauth-github'
# GITLAB patched libs
gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837"
@@ -44,7 +56,8 @@ gem "ffaker"
gem "seed-fu"
# Markdown to HTML
-gem "redcarpet", "~> 2.1.1"
+gem "redcarpet", "~> 2.1.1"
+gem "github-markup", "~> 0.7.4"
# Servers
gem "thin"
@@ -97,20 +110,28 @@ group :development do
end
group :development, :test do
+ gem 'spinach-rails'
gem "rspec-rails"
gem "capybara"
gem "capybara-webkit"
gem "headless"
- gem "autotest"
- gem "autotest-rails"
gem "pry"
gem "awesome_print"
gem "database_cleaner"
gem "launchy"
+ gem 'factory_girl_rails'
+
+ # Guard
+ gem 'guard-rspec'
+ gem 'guard-spinach'
+
+ # Notification
+ gem 'rb-fsevent', :require => darwin_only('rb-fsevent')
+ gem 'growl', :require => darwin_only('growl')
+ gem 'rb-inotify', :require => linux_only('rb-inotify')
end
group :test do
- gem 'cucumber-rails', :require => false
gem "simplecov", :require => false
gem "shoulda-matchers"
gem 'email_spec'
@@ -119,5 +140,5 @@ group :test do
end
group :production do
- gem "gitlab_meta", '2.8'
+ gem "gitlab_meta", '2.9'
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 656bede4..3d27d3fb 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -68,7 +68,6 @@ GIT
GEM
remote: http://rubygems.org/
specs:
- ZenTest (4.8.1)
actionmailer (3.2.8)
actionpack (= 3.2.8)
mail (~> 2.4.4)
@@ -100,15 +99,11 @@ GEM
rails (~> 3.0)
addressable (2.2.8)
arel (3.0.2)
- autotest (4.4.6)
- ZenTest (>= 4.4.1)
- autotest-rails (4.1.2)
- ZenTest (~> 4.5)
awesome_print (1.0.2)
bcrypt-ruby (3.0.1)
blankslate (2.1.2.4)
bootstrap-sass (2.0.4.0)
- builder (3.0.0)
+ builder (3.0.2)
capybara (1.1.2)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
@@ -125,7 +120,7 @@ GEM
charlock_holmes (0.6.8)
childprocess (0.3.2)
ffi (~> 1.0.6)
- chosen-rails (0.9.8)
+ chosen-rails (0.9.8.3)
railties (~> 3.0)
thor (~> 0.14)
coderay (1.0.6)
@@ -137,16 +132,8 @@ GEM
execjs
coffee-script-source (1.3.3)
colored (1.2)
+ colorize (0.5.8)
crack (0.3.1)
- cucumber (1.2.1)
- builder (>= 2.1.2)
- diff-lcs (>= 1.1.3)
- gherkin (~> 2.11.0)
- json (>= 1.4.6)
- cucumber-rails (1.3.0)
- capybara (>= 1.1.2)
- cucumber (>= 1.1.8)
- nokogiri (>= 1.5.0)
daemons (1.1.8)
database_cleaner (0.8.0)
devise (2.1.2)
@@ -166,20 +153,36 @@ GEM
eventmachine (0.12.10)
execjs (1.4.0)
multi_json (~> 1.0)
+ factory_girl (4.0.0)
+ activesupport (>= 3.0.0)
+ factory_girl_rails (4.0.0)
+ factory_girl (~> 4.0.0)
+ railties (>= 3.0.0)
+ faraday (0.8.4)
+ multipart-post (~> 1.1)
ffaker (1.14.0)
ffi (1.0.11)
foreman (0.47.0)
thor (>= 0.13.6)
- gherkin (2.11.0)
- json (>= 1.4.6)
+ gherkin-ruby (0.2.1)
git (1.2.5)
- gitlab_meta (2.8)
+ github-markup (0.7.4)
+ gitlab_meta (2.9)
grape (0.2.1)
hashie (~> 1.2)
multi_json
multi_xml
rack
rack-mount
+ growl (1.0.3)
+ guard (1.3.2)
+ listen (>= 0.4.2)
+ thor (>= 0.14.6)
+ guard-rspec (1.2.1)
+ guard (>= 1.1)
+ guard-spinach (0.0.2)
+ guard (>= 1.1)
+ spinach
haml (3.1.6)
haml-rails (0.3.4)
actionpack (~> 3.0)
@@ -193,7 +196,8 @@ GEM
httparty (0.8.3)
multi_json (~> 1.0)
multi_xml
- i18n (0.6.0)
+ httpauth (0.1)
+ i18n (0.6.1)
journey (1.0.4)
jquery-rails (2.0.2)
railties (>= 3.2.0, < 5.0)
@@ -201,11 +205,12 @@ GEM
jquery-ui-rails (0.5.0)
jquery-rails
railties (>= 3.1.0)
- json (1.7.4)
- kaminari (0.13.0)
+ json (1.7.5)
+ jwt (0.1.5)
+ multi_json (>= 1.0)
+ kaminari (0.14.0)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
- railties (>= 3.0.0)
kgio (2.7.4)
launchy (2.1.0)
addressable (~> 2.2.6)
@@ -214,6 +219,7 @@ GEM
libv8 (3.3.10.4)
libwebsocket (0.1.3)
addressable
+ listen (0.5.0)
mail (2.4.4)
i18n (>= 0.4.0)
mime-types (~> 1.16)
@@ -224,12 +230,35 @@ GEM
sprockets (~> 2.0)
multi_json (1.3.6)
multi_xml (0.5.1)
+ multipart-post (1.1.5)
mysql2 (0.3.11)
net-ldap (0.2.2)
nokogiri (1.5.3)
+ oauth (0.4.7)
+ oauth2 (0.8.0)
+ faraday (~> 0.8)
+ httpauth (~> 0.1)
+ jwt (~> 0.1.4)
+ multi_json (~> 1.0)
+ rack (~> 1.2)
omniauth (1.1.0)
hashie (~> 1.2)
rack
+ omniauth-github (1.0.3)
+ omniauth (~> 1.0)
+ omniauth-oauth2 (~> 1.1)
+ omniauth-google-oauth2 (0.1.13)
+ omniauth (~> 1.0)
+ omniauth-oauth2
+ omniauth-oauth (1.0.1)
+ oauth
+ omniauth (~> 1.0)
+ omniauth-oauth2 (1.1.0)
+ oauth2 (~> 0.8.0)
+ omniauth (~> 1.0)
+ omniauth-twitter (0.0.13)
+ multi_json (~> 1.3)
+ omniauth-oauth (~> 1.0)
orm_adapter (0.3.0)
polyglot (0.3.3)
posix-spawn (0.3.6)
@@ -269,6 +298,9 @@ GEM
raindrops (0.9.0)
rake (0.9.2.2)
raphael-rails (1.5.2)
+ rb-fsevent (0.9.1)
+ rb-inotify (0.8.8)
+ ffi (>= 0.5.0)
rdoc (3.12)
json (~> 1.4)
redcarpet (2.1.1)
@@ -319,7 +351,7 @@ GEM
multi_json (~> 1.0)
rubyzip
settingslogic (2.0.8)
- shoulda-matchers (1.1.0)
+ shoulda-matchers (1.3.0)
activesupport (>= 3.0.0)
simplecov (0.6.4)
multi_json (~> 1.0)
@@ -331,6 +363,13 @@ GEM
tilt (~> 1.3, >= 1.3.3)
six (0.2.0)
slop (2.4.4)
+ spinach (0.5.2)
+ colorize
+ gherkin-ruby (~> 0.2.0)
+ spinach-rails (0.1.8)
+ capybara (~> 1)
+ railties (>= 3)
+ spinach (>= 0.4)
sprockets (2.1.3)
hike (~> 1.2)
rack (~> 1.0)
@@ -343,7 +382,7 @@ GEM
daemons (>= 1.0.9)
eventmachine (>= 0.12.6)
rack (>= 1.0.0)
- thor (0.15.4)
+ thor (0.16.0)
tilt (1.3.3)
treetop (1.4.10)
polyglot
@@ -372,8 +411,6 @@ PLATFORMS
DEPENDENCIES
acts-as-taggable-on (= 2.3.1)
annotate!
- autotest
- autotest-rails
awesome_print
bootstrap-sass (= 2.0.4)
capybara
@@ -383,19 +420,23 @@ DEPENDENCIES
chosen-rails
coffee-rails (= 3.2.2)
colored
- cucumber-rails
database_cleaner
devise (~> 2.1.0)
draper
email_spec
+ factory_girl_rails
ffaker
foreman
git
- gitlab_meta (= 2.8)
+ github-markup (~> 0.7.4)
+ gitlab_meta (= 2.9)
gitolite!
grack!
grape (~> 0.2.1)
grit!
+ growl
+ guard-rspec
+ guard-spinach
haml-rails
headless
httparty
@@ -407,12 +448,18 @@ DEPENDENCIES
linguist (~> 1.0.0)!
modernizr (= 2.5.3)
mysql2
+ omniauth
+ omniauth-github
+ omniauth-google-oauth2
omniauth-ldap!
+ omniauth-twitter
pry
pygments.rb!
rack-mini-profiler
rails (= 3.2.8)
raphael-rails (= 1.5.2)
+ rb-fsevent
+ rb-inotify
redcarpet (~> 2.1.1)
resque (~> 1.20.0)
resque_mailer
@@ -424,6 +471,7 @@ DEPENDENCIES
shoulda-matchers
simplecov
six
+ spinach-rails
sqlite3
stamp
therubyracer
diff --git a/Guardfile b/Guardfile
new file mode 100644
index 00000000..e682f0b6
--- /dev/null
+++ b/Guardfile
@@ -0,0 +1,27 @@
+# A sample Guardfile
+# More info at https://github.com/guard/guard#readme
+
+guard 'rspec', :version => 2, :all_on_start => false, :all_after_pass => false do
+ watch(%r{^spec/.+_spec\.rb$})
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
+ watch(%r{^lib/api/(.+)\.rb$}) { |m| "spec/requests/api/#{m[1]}_spec.rb" }
+ watch('spec/spec_helper.rb') { "spec" }
+
+ # Rails example
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
+ watch('config/routes.rb') { "spec/routing" }
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
+
+ # Capybara request specs
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
+end
+
+guard 'spinach' do
+ watch(%r|^features/(.*)\.feature|)
+ watch(%r|^features/steps/(.*)([^/]+)\.rb|) do |m|
+ "features/#{m[1]}#{m[2]}.feature"
+ end
+end
diff --git a/README.md b/README.md
index 26ed209e..122cd984 100644
--- a/README.md
+++ b/README.md
@@ -39,5 +39,6 @@ Email
## Contribute
+[Development Tips](https://github.com/gitlabhq/gitlabhq/blob/master/doc/development.md)
Want to help - send a pull request.
We'll accept good pull requests.
diff --git a/VERSION b/VERSION
index 1817afea..c8e38b61 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.8.2
+2.9.0
diff --git a/app/assets/images/emoji/+1.png b/app/assets/images/emoji/+1.png
new file mode 100755
index 00000000..3a43ecae
Binary files /dev/null and b/app/assets/images/emoji/+1.png differ
diff --git a/app/assets/images/emoji/-1.png b/app/assets/images/emoji/-1.png
new file mode 100755
index 00000000..41c6b825
Binary files /dev/null and b/app/assets/images/emoji/-1.png differ
diff --git a/app/assets/images/emoji/100.png b/app/assets/images/emoji/100.png
new file mode 100755
index 00000000..bce9ab14
Binary files /dev/null and b/app/assets/images/emoji/100.png differ
diff --git a/app/assets/images/emoji/109.png b/app/assets/images/emoji/109.png
new file mode 100755
index 00000000..74b9d5d3
Binary files /dev/null and b/app/assets/images/emoji/109.png differ
diff --git a/app/assets/images/emoji/1234.png b/app/assets/images/emoji/1234.png
new file mode 100755
index 00000000..c47c2e1f
Binary files /dev/null and b/app/assets/images/emoji/1234.png differ
diff --git a/app/assets/images/emoji/8ball.png b/app/assets/images/emoji/8ball.png
new file mode 100755
index 00000000..c2c710d4
Binary files /dev/null and b/app/assets/images/emoji/8ball.png differ
diff --git a/app/assets/images/emoji/a.png b/app/assets/images/emoji/a.png
new file mode 100755
index 00000000..09ff6d6f
Binary files /dev/null and b/app/assets/images/emoji/a.png differ
diff --git a/app/assets/images/emoji/ab.png b/app/assets/images/emoji/ab.png
new file mode 100755
index 00000000..2a522204
Binary files /dev/null and b/app/assets/images/emoji/ab.png differ
diff --git a/app/assets/images/emoji/abc.png b/app/assets/images/emoji/abc.png
new file mode 100755
index 00000000..505d40a1
Binary files /dev/null and b/app/assets/images/emoji/abc.png differ
diff --git a/app/assets/images/emoji/abcd.png b/app/assets/images/emoji/abcd.png
new file mode 100755
index 00000000..5218470b
Binary files /dev/null and b/app/assets/images/emoji/abcd.png differ
diff --git a/app/assets/images/emoji/accept.png b/app/assets/images/emoji/accept.png
new file mode 100755
index 00000000..2d200903
Binary files /dev/null and b/app/assets/images/emoji/accept.png differ
diff --git a/app/assets/images/emoji/aerial_tramway.png b/app/assets/images/emoji/aerial_tramway.png
new file mode 100755
index 00000000..38f6dfe2
Binary files /dev/null and b/app/assets/images/emoji/aerial_tramway.png differ
diff --git a/app/assets/images/emoji/airplane.png b/app/assets/images/emoji/airplane.png
new file mode 100755
index 00000000..8407cb67
Binary files /dev/null and b/app/assets/images/emoji/airplane.png differ
diff --git a/app/assets/images/emoji/alarm_clock.png b/app/assets/images/emoji/alarm_clock.png
new file mode 100755
index 00000000..86ca8c8e
Binary files /dev/null and b/app/assets/images/emoji/alarm_clock.png differ
diff --git a/app/assets/images/emoji/alien.png b/app/assets/images/emoji/alien.png
new file mode 100755
index 00000000..416de47b
Binary files /dev/null and b/app/assets/images/emoji/alien.png differ
diff --git a/app/assets/images/emoji/ambulance.png b/app/assets/images/emoji/ambulance.png
new file mode 100755
index 00000000..b740f45d
Binary files /dev/null and b/app/assets/images/emoji/ambulance.png differ
diff --git a/app/assets/images/emoji/anchor.png b/app/assets/images/emoji/anchor.png
new file mode 100755
index 00000000..0c5192e6
Binary files /dev/null and b/app/assets/images/emoji/anchor.png differ
diff --git a/app/assets/images/emoji/angel.png b/app/assets/images/emoji/angel.png
new file mode 100755
index 00000000..da52c310
Binary files /dev/null and b/app/assets/images/emoji/angel.png differ
diff --git a/app/assets/images/emoji/anger.png b/app/assets/images/emoji/anger.png
new file mode 100755
index 00000000..6fb4dca1
Binary files /dev/null and b/app/assets/images/emoji/anger.png differ
diff --git a/app/assets/images/emoji/angry.png b/app/assets/images/emoji/angry.png
new file mode 100755
index 00000000..f95bfa89
Binary files /dev/null and b/app/assets/images/emoji/angry.png differ
diff --git a/app/assets/images/emoji/ant.png b/app/assets/images/emoji/ant.png
new file mode 100755
index 00000000..b92d1cc1
Binary files /dev/null and b/app/assets/images/emoji/ant.png differ
diff --git a/app/assets/images/emoji/apple.png b/app/assets/images/emoji/apple.png
new file mode 100755
index 00000000..08aa17b9
Binary files /dev/null and b/app/assets/images/emoji/apple.png differ
diff --git a/app/assets/images/emoji/aquarius.png b/app/assets/images/emoji/aquarius.png
new file mode 100755
index 00000000..cbff66ed
Binary files /dev/null and b/app/assets/images/emoji/aquarius.png differ
diff --git a/app/assets/images/emoji/aries.png b/app/assets/images/emoji/aries.png
new file mode 100755
index 00000000..89990223
Binary files /dev/null and b/app/assets/images/emoji/aries.png differ
diff --git a/app/assets/images/emoji/arrow_backward.png b/app/assets/images/emoji/arrow_backward.png
new file mode 100755
index 00000000..08862183
Binary files /dev/null and b/app/assets/images/emoji/arrow_backward.png differ
diff --git a/app/assets/images/emoji/arrow_double_down.png b/app/assets/images/emoji/arrow_double_down.png
new file mode 100755
index 00000000..2ecbebcd
Binary files /dev/null and b/app/assets/images/emoji/arrow_double_down.png differ
diff --git a/app/assets/images/emoji/arrow_double_up.png b/app/assets/images/emoji/arrow_double_up.png
new file mode 100755
index 00000000..d42979d4
Binary files /dev/null and b/app/assets/images/emoji/arrow_double_up.png differ
diff --git a/app/assets/images/emoji/arrow_down.png b/app/assets/images/emoji/arrow_down.png
new file mode 100755
index 00000000..e6702f02
Binary files /dev/null and b/app/assets/images/emoji/arrow_down.png differ
diff --git a/app/assets/images/emoji/arrow_down_small.png b/app/assets/images/emoji/arrow_down_small.png
new file mode 100755
index 00000000..f7f2d510
Binary files /dev/null and b/app/assets/images/emoji/arrow_down_small.png differ
diff --git a/app/assets/images/emoji/arrow_forward.png b/app/assets/images/emoji/arrow_forward.png
new file mode 100755
index 00000000..fbfe711b
Binary files /dev/null and b/app/assets/images/emoji/arrow_forward.png differ
diff --git a/app/assets/images/emoji/arrow_heading_down.png b/app/assets/images/emoji/arrow_heading_down.png
new file mode 100755
index 00000000..56dd3b9d
Binary files /dev/null and b/app/assets/images/emoji/arrow_heading_down.png differ
diff --git a/app/assets/images/emoji/arrow_heading_up.png b/app/assets/images/emoji/arrow_heading_up.png
new file mode 100755
index 00000000..c8f670a1
Binary files /dev/null and b/app/assets/images/emoji/arrow_heading_up.png differ
diff --git a/app/assets/images/emoji/arrow_left.png b/app/assets/images/emoji/arrow_left.png
new file mode 100755
index 00000000..d64ac619
Binary files /dev/null and b/app/assets/images/emoji/arrow_left.png differ
diff --git a/app/assets/images/emoji/arrow_lower_left.png b/app/assets/images/emoji/arrow_lower_left.png
new file mode 100755
index 00000000..55fb03c4
Binary files /dev/null and b/app/assets/images/emoji/arrow_lower_left.png differ
diff --git a/app/assets/images/emoji/arrow_lower_right.png b/app/assets/images/emoji/arrow_lower_right.png
new file mode 100755
index 00000000..da8fb829
Binary files /dev/null and b/app/assets/images/emoji/arrow_lower_right.png differ
diff --git a/app/assets/images/emoji/arrow_right.png b/app/assets/images/emoji/arrow_right.png
new file mode 100755
index 00000000..6d483b51
Binary files /dev/null and b/app/assets/images/emoji/arrow_right.png differ
diff --git a/app/assets/images/emoji/arrow_right_hook.png b/app/assets/images/emoji/arrow_right_hook.png
new file mode 100755
index 00000000..8b4ea6e1
Binary files /dev/null and b/app/assets/images/emoji/arrow_right_hook.png differ
diff --git a/app/assets/images/emoji/arrow_up.png b/app/assets/images/emoji/arrow_up.png
new file mode 100755
index 00000000..b5b0688d
Binary files /dev/null and b/app/assets/images/emoji/arrow_up.png differ
diff --git a/app/assets/images/emoji/arrow_up_down.png b/app/assets/images/emoji/arrow_up_down.png
new file mode 100755
index 00000000..b718c214
Binary files /dev/null and b/app/assets/images/emoji/arrow_up_down.png differ
diff --git a/app/assets/images/emoji/arrow_up_small.png b/app/assets/images/emoji/arrow_up_small.png
new file mode 100755
index 00000000..12173319
Binary files /dev/null and b/app/assets/images/emoji/arrow_up_small.png differ
diff --git a/app/assets/images/emoji/arrow_upper_left.png b/app/assets/images/emoji/arrow_upper_left.png
new file mode 100755
index 00000000..e895fd7b
Binary files /dev/null and b/app/assets/images/emoji/arrow_upper_left.png differ
diff --git a/app/assets/images/emoji/arrow_upper_right.png b/app/assets/images/emoji/arrow_upper_right.png
new file mode 100755
index 00000000..e23790ba
Binary files /dev/null and b/app/assets/images/emoji/arrow_upper_right.png differ
diff --git a/app/assets/images/emoji/arrows_clockwise.png b/app/assets/images/emoji/arrows_clockwise.png
new file mode 100755
index 00000000..5f84d7e7
Binary files /dev/null and b/app/assets/images/emoji/arrows_clockwise.png differ
diff --git a/app/assets/images/emoji/arrows_counterclockwise.png b/app/assets/images/emoji/arrows_counterclockwise.png
new file mode 100755
index 00000000..1933ae18
Binary files /dev/null and b/app/assets/images/emoji/arrows_counterclockwise.png differ
diff --git a/app/assets/images/emoji/art.png b/app/assets/images/emoji/art.png
new file mode 100755
index 00000000..d45212b0
Binary files /dev/null and b/app/assets/images/emoji/art.png differ
diff --git a/app/assets/images/emoji/articulated_lorry.png b/app/assets/images/emoji/articulated_lorry.png
new file mode 100755
index 00000000..81ec1f91
Binary files /dev/null and b/app/assets/images/emoji/articulated_lorry.png differ
diff --git a/app/assets/images/emoji/astonished.png b/app/assets/images/emoji/astonished.png
new file mode 100755
index 00000000..858a8348
Binary files /dev/null and b/app/assets/images/emoji/astonished.png differ
diff --git a/app/assets/images/emoji/atm.png b/app/assets/images/emoji/atm.png
new file mode 100755
index 00000000..c2846e79
Binary files /dev/null and b/app/assets/images/emoji/atm.png differ
diff --git a/app/assets/images/emoji/b.png b/app/assets/images/emoji/b.png
new file mode 100755
index 00000000..8742b3d2
Binary files /dev/null and b/app/assets/images/emoji/b.png differ
diff --git a/app/assets/images/emoji/baby.png b/app/assets/images/emoji/baby.png
new file mode 100755
index 00000000..3b29da40
Binary files /dev/null and b/app/assets/images/emoji/baby.png differ
diff --git a/app/assets/images/emoji/baby_bottle.png b/app/assets/images/emoji/baby_bottle.png
new file mode 100755
index 00000000..1b2cfe5e
Binary files /dev/null and b/app/assets/images/emoji/baby_bottle.png differ
diff --git a/app/assets/images/emoji/baby_chick.png b/app/assets/images/emoji/baby_chick.png
new file mode 100755
index 00000000..9be8d293
Binary files /dev/null and b/app/assets/images/emoji/baby_chick.png differ
diff --git a/app/assets/images/emoji/baby_symbol.png b/app/assets/images/emoji/baby_symbol.png
new file mode 100755
index 00000000..2e58725c
Binary files /dev/null and b/app/assets/images/emoji/baby_symbol.png differ
diff --git a/app/assets/images/emoji/baggage_claim.png b/app/assets/images/emoji/baggage_claim.png
new file mode 100755
index 00000000..59ae044a
Binary files /dev/null and b/app/assets/images/emoji/baggage_claim.png differ
diff --git a/app/assets/images/emoji/balloon.png b/app/assets/images/emoji/balloon.png
new file mode 100755
index 00000000..03448970
Binary files /dev/null and b/app/assets/images/emoji/balloon.png differ
diff --git a/app/assets/images/emoji/ballot_box_with_check.png b/app/assets/images/emoji/ballot_box_with_check.png
new file mode 100755
index 00000000..f07a466c
Binary files /dev/null and b/app/assets/images/emoji/ballot_box_with_check.png differ
diff --git a/app/assets/images/emoji/bamboo.png b/app/assets/images/emoji/bamboo.png
new file mode 100755
index 00000000..fc858d0f
Binary files /dev/null and b/app/assets/images/emoji/bamboo.png differ
diff --git a/app/assets/images/emoji/banana.png b/app/assets/images/emoji/banana.png
new file mode 100755
index 00000000..a0563afb
Binary files /dev/null and b/app/assets/images/emoji/banana.png differ
diff --git a/app/assets/images/emoji/bangbang.png b/app/assets/images/emoji/bangbang.png
new file mode 100755
index 00000000..7270f0af
Binary files /dev/null and b/app/assets/images/emoji/bangbang.png differ
diff --git a/app/assets/images/emoji/bank.png b/app/assets/images/emoji/bank.png
new file mode 100755
index 00000000..1faa8777
Binary files /dev/null and b/app/assets/images/emoji/bank.png differ
diff --git a/app/assets/images/emoji/bar_chart.png b/app/assets/images/emoji/bar_chart.png
new file mode 100755
index 00000000..7871cc60
Binary files /dev/null and b/app/assets/images/emoji/bar_chart.png differ
diff --git a/app/assets/images/emoji/barber.png b/app/assets/images/emoji/barber.png
new file mode 100755
index 00000000..a10cb232
Binary files /dev/null and b/app/assets/images/emoji/barber.png differ
diff --git a/app/assets/images/emoji/baseball.png b/app/assets/images/emoji/baseball.png
new file mode 100755
index 00000000..da004e2e
Binary files /dev/null and b/app/assets/images/emoji/baseball.png differ
diff --git a/app/assets/images/emoji/basketball.png b/app/assets/images/emoji/basketball.png
new file mode 100755
index 00000000..ef694bec
Binary files /dev/null and b/app/assets/images/emoji/basketball.png differ
diff --git a/app/assets/images/emoji/bath.png b/app/assets/images/emoji/bath.png
new file mode 100755
index 00000000..8f75d1d2
Binary files /dev/null and b/app/assets/images/emoji/bath.png differ
diff --git a/app/assets/images/emoji/bathtub.png b/app/assets/images/emoji/bathtub.png
new file mode 100755
index 00000000..1c3f844a
Binary files /dev/null and b/app/assets/images/emoji/bathtub.png differ
diff --git a/app/assets/images/emoji/battery.png b/app/assets/images/emoji/battery.png
new file mode 100755
index 00000000..aa7eedce
Binary files /dev/null and b/app/assets/images/emoji/battery.png differ
diff --git a/app/assets/images/emoji/bear.png b/app/assets/images/emoji/bear.png
new file mode 100755
index 00000000..f5afe920
Binary files /dev/null and b/app/assets/images/emoji/bear.png differ
diff --git a/app/assets/images/emoji/beer.png b/app/assets/images/emoji/beer.png
new file mode 100755
index 00000000..cd78bed7
Binary files /dev/null and b/app/assets/images/emoji/beer.png differ
diff --git a/app/assets/images/emoji/beers.png b/app/assets/images/emoji/beers.png
new file mode 100755
index 00000000..cc5e4ab5
Binary files /dev/null and b/app/assets/images/emoji/beers.png differ
diff --git a/app/assets/images/emoji/beetle.png b/app/assets/images/emoji/beetle.png
new file mode 100755
index 00000000..222577ca
Binary files /dev/null and b/app/assets/images/emoji/beetle.png differ
diff --git a/app/assets/images/emoji/beginner.png b/app/assets/images/emoji/beginner.png
new file mode 100755
index 00000000..1f022d17
Binary files /dev/null and b/app/assets/images/emoji/beginner.png differ
diff --git a/app/assets/images/emoji/bell.png b/app/assets/images/emoji/bell.png
new file mode 100755
index 00000000..69acceb2
Binary files /dev/null and b/app/assets/images/emoji/bell.png differ
diff --git a/app/assets/images/emoji/bento.png b/app/assets/images/emoji/bento.png
new file mode 100755
index 00000000..c6d99e89
Binary files /dev/null and b/app/assets/images/emoji/bento.png differ
diff --git a/app/assets/images/emoji/bicyclist.png b/app/assets/images/emoji/bicyclist.png
new file mode 100755
index 00000000..4e3e0549
Binary files /dev/null and b/app/assets/images/emoji/bicyclist.png differ
diff --git a/app/assets/images/emoji/bike.png b/app/assets/images/emoji/bike.png
new file mode 100755
index 00000000..65738602
Binary files /dev/null and b/app/assets/images/emoji/bike.png differ
diff --git a/app/assets/images/emoji/bikini.png b/app/assets/images/emoji/bikini.png
new file mode 100755
index 00000000..4ff63b40
Binary files /dev/null and b/app/assets/images/emoji/bikini.png differ
diff --git a/app/assets/images/emoji/bird.png b/app/assets/images/emoji/bird.png
new file mode 100755
index 00000000..e6be8c02
Binary files /dev/null and b/app/assets/images/emoji/bird.png differ
diff --git a/app/assets/images/emoji/birthday.png b/app/assets/images/emoji/birthday.png
new file mode 100755
index 00000000..36e8edcb
Binary files /dev/null and b/app/assets/images/emoji/birthday.png differ
diff --git a/app/assets/images/emoji/black_circle.png b/app/assets/images/emoji/black_circle.png
new file mode 100755
index 00000000..e46f9df6
Binary files /dev/null and b/app/assets/images/emoji/black_circle.png differ
diff --git a/app/assets/images/emoji/black_joker.png b/app/assets/images/emoji/black_joker.png
new file mode 100755
index 00000000..4c78f361
Binary files /dev/null and b/app/assets/images/emoji/black_joker.png differ
diff --git a/app/assets/images/emoji/black_nib.png b/app/assets/images/emoji/black_nib.png
new file mode 100755
index 00000000..29f6994c
Binary files /dev/null and b/app/assets/images/emoji/black_nib.png differ
diff --git a/app/assets/images/emoji/black_square.png b/app/assets/images/emoji/black_square.png
new file mode 100755
index 00000000..71da10de
Binary files /dev/null and b/app/assets/images/emoji/black_square.png differ
diff --git a/app/assets/images/emoji/blossom.png b/app/assets/images/emoji/blossom.png
new file mode 100755
index 00000000..55a97353
Binary files /dev/null and b/app/assets/images/emoji/blossom.png differ
diff --git a/app/assets/images/emoji/blowfish.png b/app/assets/images/emoji/blowfish.png
new file mode 100755
index 00000000..a1d47cb7
Binary files /dev/null and b/app/assets/images/emoji/blowfish.png differ
diff --git a/app/assets/images/emoji/blue_book.png b/app/assets/images/emoji/blue_book.png
new file mode 100755
index 00000000..e2b9e8c7
Binary files /dev/null and b/app/assets/images/emoji/blue_book.png differ
diff --git a/app/assets/images/emoji/blue_car.png b/app/assets/images/emoji/blue_car.png
new file mode 100755
index 00000000..978291e0
Binary files /dev/null and b/app/assets/images/emoji/blue_car.png differ
diff --git a/app/assets/images/emoji/blue_heart.png b/app/assets/images/emoji/blue_heart.png
new file mode 100755
index 00000000..baa29b31
Binary files /dev/null and b/app/assets/images/emoji/blue_heart.png differ
diff --git a/app/assets/images/emoji/blush.png b/app/assets/images/emoji/blush.png
new file mode 100755
index 00000000..3a95eb61
Binary files /dev/null and b/app/assets/images/emoji/blush.png differ
diff --git a/app/assets/images/emoji/boar.png b/app/assets/images/emoji/boar.png
new file mode 100755
index 00000000..8196ad4a
Binary files /dev/null and b/app/assets/images/emoji/boar.png differ
diff --git a/app/assets/images/emoji/boat.png b/app/assets/images/emoji/boat.png
new file mode 100755
index 00000000..ff656dc6
Binary files /dev/null and b/app/assets/images/emoji/boat.png differ
diff --git a/app/assets/images/emoji/bomb.png b/app/assets/images/emoji/bomb.png
new file mode 100755
index 00000000..3289787d
Binary files /dev/null and b/app/assets/images/emoji/bomb.png differ
diff --git a/app/assets/images/emoji/book.png b/app/assets/images/emoji/book.png
new file mode 100755
index 00000000..8b698415
Binary files /dev/null and b/app/assets/images/emoji/book.png differ
diff --git a/app/assets/images/emoji/bookmark.png b/app/assets/images/emoji/bookmark.png
new file mode 100755
index 00000000..dbee45c6
Binary files /dev/null and b/app/assets/images/emoji/bookmark.png differ
diff --git a/app/assets/images/emoji/bookmark_tabs.png b/app/assets/images/emoji/bookmark_tabs.png
new file mode 100755
index 00000000..0c4e3bf1
Binary files /dev/null and b/app/assets/images/emoji/bookmark_tabs.png differ
diff --git a/app/assets/images/emoji/books.png b/app/assets/images/emoji/books.png
new file mode 100755
index 00000000..dca06a1a
Binary files /dev/null and b/app/assets/images/emoji/books.png differ
diff --git a/app/assets/images/emoji/boot.png b/app/assets/images/emoji/boot.png
new file mode 100755
index 00000000..58d0fdbc
Binary files /dev/null and b/app/assets/images/emoji/boot.png differ
diff --git a/app/assets/images/emoji/bouquet.png b/app/assets/images/emoji/bouquet.png
new file mode 100755
index 00000000..ce637832
Binary files /dev/null and b/app/assets/images/emoji/bouquet.png differ
diff --git a/app/assets/images/emoji/bow.png b/app/assets/images/emoji/bow.png
new file mode 100755
index 00000000..024cb610
Binary files /dev/null and b/app/assets/images/emoji/bow.png differ
diff --git a/app/assets/images/emoji/bowling.png b/app/assets/images/emoji/bowling.png
new file mode 100755
index 00000000..13d8ece2
Binary files /dev/null and b/app/assets/images/emoji/bowling.png differ
diff --git a/app/assets/images/emoji/bowtie.png b/app/assets/images/emoji/bowtie.png
new file mode 100755
index 00000000..28ff0c78
Binary files /dev/null and b/app/assets/images/emoji/bowtie.png differ
diff --git a/app/assets/images/emoji/boy.png b/app/assets/images/emoji/boy.png
new file mode 100755
index 00000000..f79f1f29
Binary files /dev/null and b/app/assets/images/emoji/boy.png differ
diff --git a/app/assets/images/emoji/bread.png b/app/assets/images/emoji/bread.png
new file mode 100755
index 00000000..7e7c6375
Binary files /dev/null and b/app/assets/images/emoji/bread.png differ
diff --git a/app/assets/images/emoji/bride_with_veil.png b/app/assets/images/emoji/bride_with_veil.png
new file mode 100755
index 00000000..dd0b0cfd
Binary files /dev/null and b/app/assets/images/emoji/bride_with_veil.png differ
diff --git a/app/assets/images/emoji/bridge_at_night.png b/app/assets/images/emoji/bridge_at_night.png
new file mode 100755
index 00000000..495b06c3
Binary files /dev/null and b/app/assets/images/emoji/bridge_at_night.png differ
diff --git a/app/assets/images/emoji/briefcase.png b/app/assets/images/emoji/briefcase.png
new file mode 100755
index 00000000..46e82b00
Binary files /dev/null and b/app/assets/images/emoji/briefcase.png differ
diff --git a/app/assets/images/emoji/broken_heart.png b/app/assets/images/emoji/broken_heart.png
new file mode 100755
index 00000000..a1bc850e
Binary files /dev/null and b/app/assets/images/emoji/broken_heart.png differ
diff --git a/app/assets/images/emoji/bug.png b/app/assets/images/emoji/bug.png
new file mode 100755
index 00000000..c2eaf7a7
Binary files /dev/null and b/app/assets/images/emoji/bug.png differ
diff --git a/app/assets/images/emoji/bulb.png b/app/assets/images/emoji/bulb.png
new file mode 100755
index 00000000..23afca1c
Binary files /dev/null and b/app/assets/images/emoji/bulb.png differ
diff --git a/app/assets/images/emoji/bullettrain_front.png b/app/assets/images/emoji/bullettrain_front.png
new file mode 100755
index 00000000..16651acf
Binary files /dev/null and b/app/assets/images/emoji/bullettrain_front.png differ
diff --git a/app/assets/images/emoji/bullettrain_side.png b/app/assets/images/emoji/bullettrain_side.png
new file mode 100755
index 00000000..8eca3684
Binary files /dev/null and b/app/assets/images/emoji/bullettrain_side.png differ
diff --git a/app/assets/images/emoji/bus.png b/app/assets/images/emoji/bus.png
new file mode 100755
index 00000000..823aa39e
Binary files /dev/null and b/app/assets/images/emoji/bus.png differ
diff --git a/app/assets/images/emoji/busstop.png b/app/assets/images/emoji/busstop.png
new file mode 100755
index 00000000..94894847
Binary files /dev/null and b/app/assets/images/emoji/busstop.png differ
diff --git a/app/assets/images/emoji/bust_in_silhouette.png b/app/assets/images/emoji/bust_in_silhouette.png
new file mode 100755
index 00000000..d1313986
Binary files /dev/null and b/app/assets/images/emoji/bust_in_silhouette.png differ
diff --git a/app/assets/images/emoji/busts_in_silhouette.png b/app/assets/images/emoji/busts_in_silhouette.png
new file mode 100755
index 00000000..1f3aabcf
Binary files /dev/null and b/app/assets/images/emoji/busts_in_silhouette.png differ
diff --git a/app/assets/images/emoji/cactus.png b/app/assets/images/emoji/cactus.png
new file mode 100755
index 00000000..5a2c3cc7
Binary files /dev/null and b/app/assets/images/emoji/cactus.png differ
diff --git a/app/assets/images/emoji/cake.png b/app/assets/images/emoji/cake.png
new file mode 100755
index 00000000..efeb9b4b
Binary files /dev/null and b/app/assets/images/emoji/cake.png differ
diff --git a/app/assets/images/emoji/calendar.png b/app/assets/images/emoji/calendar.png
new file mode 100755
index 00000000..900b868b
Binary files /dev/null and b/app/assets/images/emoji/calendar.png differ
diff --git a/app/assets/images/emoji/calling.png b/app/assets/images/emoji/calling.png
new file mode 100755
index 00000000..837897f2
Binary files /dev/null and b/app/assets/images/emoji/calling.png differ
diff --git a/app/assets/images/emoji/camel.png b/app/assets/images/emoji/camel.png
new file mode 100755
index 00000000..496c186a
Binary files /dev/null and b/app/assets/images/emoji/camel.png differ
diff --git a/app/assets/images/emoji/camera.png b/app/assets/images/emoji/camera.png
new file mode 100755
index 00000000..397d03b3
Binary files /dev/null and b/app/assets/images/emoji/camera.png differ
diff --git a/app/assets/images/emoji/cancer.png b/app/assets/images/emoji/cancer.png
new file mode 100755
index 00000000..ea43a4a2
Binary files /dev/null and b/app/assets/images/emoji/cancer.png differ
diff --git a/app/assets/images/emoji/candy.png b/app/assets/images/emoji/candy.png
new file mode 100755
index 00000000..33722f23
Binary files /dev/null and b/app/assets/images/emoji/candy.png differ
diff --git a/app/assets/images/emoji/capital_abcd.png b/app/assets/images/emoji/capital_abcd.png
new file mode 100755
index 00000000..ffc0cba4
Binary files /dev/null and b/app/assets/images/emoji/capital_abcd.png differ
diff --git a/app/assets/images/emoji/capricorn.png b/app/assets/images/emoji/capricorn.png
new file mode 100755
index 00000000..f2044e78
Binary files /dev/null and b/app/assets/images/emoji/capricorn.png differ
diff --git a/app/assets/images/emoji/car.png b/app/assets/images/emoji/car.png
new file mode 100755
index 00000000..d70a2f06
Binary files /dev/null and b/app/assets/images/emoji/car.png differ
diff --git a/app/assets/images/emoji/card_index.png b/app/assets/images/emoji/card_index.png
new file mode 100755
index 00000000..374e94e9
Binary files /dev/null and b/app/assets/images/emoji/card_index.png differ
diff --git a/app/assets/images/emoji/carousel_horse.png b/app/assets/images/emoji/carousel_horse.png
new file mode 100755
index 00000000..765d2c0a
Binary files /dev/null and b/app/assets/images/emoji/carousel_horse.png differ
diff --git a/app/assets/images/emoji/cat.png b/app/assets/images/emoji/cat.png
new file mode 100755
index 00000000..09b9ef79
Binary files /dev/null and b/app/assets/images/emoji/cat.png differ
diff --git a/app/assets/images/emoji/cat2.png b/app/assets/images/emoji/cat2.png
new file mode 100755
index 00000000..977c992c
Binary files /dev/null and b/app/assets/images/emoji/cat2.png differ
diff --git a/app/assets/images/emoji/cd.png b/app/assets/images/emoji/cd.png
new file mode 100755
index 00000000..baff835c
Binary files /dev/null and b/app/assets/images/emoji/cd.png differ
diff --git a/app/assets/images/emoji/chart.png b/app/assets/images/emoji/chart.png
new file mode 100755
index 00000000..ac2c4bb0
Binary files /dev/null and b/app/assets/images/emoji/chart.png differ
diff --git a/app/assets/images/emoji/chart_with_downwards_trend.png b/app/assets/images/emoji/chart_with_downwards_trend.png
new file mode 100755
index 00000000..65b82f04
Binary files /dev/null and b/app/assets/images/emoji/chart_with_downwards_trend.png differ
diff --git a/app/assets/images/emoji/chart_with_upwards_trend.png b/app/assets/images/emoji/chart_with_upwards_trend.png
new file mode 100755
index 00000000..de3e9ba7
Binary files /dev/null and b/app/assets/images/emoji/chart_with_upwards_trend.png differ
diff --git a/app/assets/images/emoji/checkered_flag.png b/app/assets/images/emoji/checkered_flag.png
new file mode 100755
index 00000000..ead4a68d
Binary files /dev/null and b/app/assets/images/emoji/checkered_flag.png differ
diff --git a/app/assets/images/emoji/cherries.png b/app/assets/images/emoji/cherries.png
new file mode 100755
index 00000000..8d3e044f
Binary files /dev/null and b/app/assets/images/emoji/cherries.png differ
diff --git a/app/assets/images/emoji/cherry_blossom.png b/app/assets/images/emoji/cherry_blossom.png
new file mode 100755
index 00000000..e0315549
Binary files /dev/null and b/app/assets/images/emoji/cherry_blossom.png differ
diff --git a/app/assets/images/emoji/chestnut.png b/app/assets/images/emoji/chestnut.png
new file mode 100755
index 00000000..066fb6bf
Binary files /dev/null and b/app/assets/images/emoji/chestnut.png differ
diff --git a/app/assets/images/emoji/chicken.png b/app/assets/images/emoji/chicken.png
new file mode 100755
index 00000000..6d25c0ef
Binary files /dev/null and b/app/assets/images/emoji/chicken.png differ
diff --git a/app/assets/images/emoji/children_crossing.png b/app/assets/images/emoji/children_crossing.png
new file mode 100755
index 00000000..b0302ae6
Binary files /dev/null and b/app/assets/images/emoji/children_crossing.png differ
diff --git a/app/assets/images/emoji/chocolate_bar.png b/app/assets/images/emoji/chocolate_bar.png
new file mode 100755
index 00000000..c7ec19d0
Binary files /dev/null and b/app/assets/images/emoji/chocolate_bar.png differ
diff --git a/app/assets/images/emoji/christmas_tree.png b/app/assets/images/emoji/christmas_tree.png
new file mode 100755
index 00000000..d813b959
Binary files /dev/null and b/app/assets/images/emoji/christmas_tree.png differ
diff --git a/app/assets/images/emoji/church.png b/app/assets/images/emoji/church.png
new file mode 100755
index 00000000..4c07c6b9
Binary files /dev/null and b/app/assets/images/emoji/church.png differ
diff --git a/app/assets/images/emoji/cinema.png b/app/assets/images/emoji/cinema.png
new file mode 100755
index 00000000..a990ccf9
Binary files /dev/null and b/app/assets/images/emoji/cinema.png differ
diff --git a/app/assets/images/emoji/circus_tent.png b/app/assets/images/emoji/circus_tent.png
new file mode 100755
index 00000000..4af8719a
Binary files /dev/null and b/app/assets/images/emoji/circus_tent.png differ
diff --git a/app/assets/images/emoji/city_sunrise.png b/app/assets/images/emoji/city_sunrise.png
new file mode 100755
index 00000000..91ca2a40
Binary files /dev/null and b/app/assets/images/emoji/city_sunrise.png differ
diff --git a/app/assets/images/emoji/city_sunset.png b/app/assets/images/emoji/city_sunset.png
new file mode 100755
index 00000000..7cb178a2
Binary files /dev/null and b/app/assets/images/emoji/city_sunset.png differ
diff --git a/app/assets/images/emoji/cl.png b/app/assets/images/emoji/cl.png
new file mode 100755
index 00000000..15ac6752
Binary files /dev/null and b/app/assets/images/emoji/cl.png differ
diff --git a/app/assets/images/emoji/clap.png b/app/assets/images/emoji/clap.png
new file mode 100755
index 00000000..d01c982a
Binary files /dev/null and b/app/assets/images/emoji/clap.png differ
diff --git a/app/assets/images/emoji/clapper.png b/app/assets/images/emoji/clapper.png
new file mode 100755
index 00000000..4e1dc111
Binary files /dev/null and b/app/assets/images/emoji/clapper.png differ
diff --git a/app/assets/images/emoji/clipboard.png b/app/assets/images/emoji/clipboard.png
new file mode 100755
index 00000000..e2c74e6d
Binary files /dev/null and b/app/assets/images/emoji/clipboard.png differ
diff --git a/app/assets/images/emoji/clock1.png b/app/assets/images/emoji/clock1.png
new file mode 100755
index 00000000..9174d4e0
Binary files /dev/null and b/app/assets/images/emoji/clock1.png differ
diff --git a/app/assets/images/emoji/clock10.png b/app/assets/images/emoji/clock10.png
new file mode 100755
index 00000000..39f590d6
Binary files /dev/null and b/app/assets/images/emoji/clock10.png differ
diff --git a/app/assets/images/emoji/clock1030.png b/app/assets/images/emoji/clock1030.png
new file mode 100755
index 00000000..84a3bc8f
Binary files /dev/null and b/app/assets/images/emoji/clock1030.png differ
diff --git a/app/assets/images/emoji/clock11.png b/app/assets/images/emoji/clock11.png
new file mode 100755
index 00000000..ddb53fad
Binary files /dev/null and b/app/assets/images/emoji/clock11.png differ
diff --git a/app/assets/images/emoji/clock1130.png b/app/assets/images/emoji/clock1130.png
new file mode 100755
index 00000000..415999ec
Binary files /dev/null and b/app/assets/images/emoji/clock1130.png differ
diff --git a/app/assets/images/emoji/clock12.png b/app/assets/images/emoji/clock12.png
new file mode 100755
index 00000000..87b13287
Binary files /dev/null and b/app/assets/images/emoji/clock12.png differ
diff --git a/app/assets/images/emoji/clock1230.png b/app/assets/images/emoji/clock1230.png
new file mode 100755
index 00000000..a6527154
Binary files /dev/null and b/app/assets/images/emoji/clock1230.png differ
diff --git a/app/assets/images/emoji/clock130.png b/app/assets/images/emoji/clock130.png
new file mode 100755
index 00000000..df939201
Binary files /dev/null and b/app/assets/images/emoji/clock130.png differ
diff --git a/app/assets/images/emoji/clock2.png b/app/assets/images/emoji/clock2.png
new file mode 100755
index 00000000..65b3b3af
Binary files /dev/null and b/app/assets/images/emoji/clock2.png differ
diff --git a/app/assets/images/emoji/clock230.png b/app/assets/images/emoji/clock230.png
new file mode 100755
index 00000000..f12c6912
Binary files /dev/null and b/app/assets/images/emoji/clock230.png differ
diff --git a/app/assets/images/emoji/clock3.png b/app/assets/images/emoji/clock3.png
new file mode 100755
index 00000000..3e44d64e
Binary files /dev/null and b/app/assets/images/emoji/clock3.png differ
diff --git a/app/assets/images/emoji/clock330.png b/app/assets/images/emoji/clock330.png
new file mode 100755
index 00000000..1dc9628e
Binary files /dev/null and b/app/assets/images/emoji/clock330.png differ
diff --git a/app/assets/images/emoji/clock4.png b/app/assets/images/emoji/clock4.png
new file mode 100755
index 00000000..948ed1a3
Binary files /dev/null and b/app/assets/images/emoji/clock4.png differ
diff --git a/app/assets/images/emoji/clock430.png b/app/assets/images/emoji/clock430.png
new file mode 100755
index 00000000..7726aaea
Binary files /dev/null and b/app/assets/images/emoji/clock430.png differ
diff --git a/app/assets/images/emoji/clock5.png b/app/assets/images/emoji/clock5.png
new file mode 100755
index 00000000..b010b4f8
Binary files /dev/null and b/app/assets/images/emoji/clock5.png differ
diff --git a/app/assets/images/emoji/clock530.png b/app/assets/images/emoji/clock530.png
new file mode 100755
index 00000000..e08d4ad2
Binary files /dev/null and b/app/assets/images/emoji/clock530.png differ
diff --git a/app/assets/images/emoji/clock6.png b/app/assets/images/emoji/clock6.png
new file mode 100755
index 00000000..76bf8cf1
Binary files /dev/null and b/app/assets/images/emoji/clock6.png differ
diff --git a/app/assets/images/emoji/clock630.png b/app/assets/images/emoji/clock630.png
new file mode 100755
index 00000000..46f0681f
Binary files /dev/null and b/app/assets/images/emoji/clock630.png differ
diff --git a/app/assets/images/emoji/clock7.png b/app/assets/images/emoji/clock7.png
new file mode 100755
index 00000000..d48f645d
Binary files /dev/null and b/app/assets/images/emoji/clock7.png differ
diff --git a/app/assets/images/emoji/clock730.png b/app/assets/images/emoji/clock730.png
new file mode 100755
index 00000000..18aab22f
Binary files /dev/null and b/app/assets/images/emoji/clock730.png differ
diff --git a/app/assets/images/emoji/clock8.png b/app/assets/images/emoji/clock8.png
new file mode 100755
index 00000000..74c770d8
Binary files /dev/null and b/app/assets/images/emoji/clock8.png differ
diff --git a/app/assets/images/emoji/clock830.png b/app/assets/images/emoji/clock830.png
new file mode 100755
index 00000000..ec3e382d
Binary files /dev/null and b/app/assets/images/emoji/clock830.png differ
diff --git a/app/assets/images/emoji/clock9.png b/app/assets/images/emoji/clock9.png
new file mode 100755
index 00000000..f009d14a
Binary files /dev/null and b/app/assets/images/emoji/clock9.png differ
diff --git a/app/assets/images/emoji/clock930.png b/app/assets/images/emoji/clock930.png
new file mode 100755
index 00000000..fd352214
Binary files /dev/null and b/app/assets/images/emoji/clock930.png differ
diff --git a/app/assets/images/emoji/closed_book.png b/app/assets/images/emoji/closed_book.png
new file mode 100755
index 00000000..484029c5
Binary files /dev/null and b/app/assets/images/emoji/closed_book.png differ
diff --git a/app/assets/images/emoji/closed_lock_with_key.png b/app/assets/images/emoji/closed_lock_with_key.png
new file mode 100755
index 00000000..e6fdf6cb
Binary files /dev/null and b/app/assets/images/emoji/closed_lock_with_key.png differ
diff --git a/app/assets/images/emoji/closed_umbrella.png b/app/assets/images/emoji/closed_umbrella.png
new file mode 100755
index 00000000..0b719f08
Binary files /dev/null and b/app/assets/images/emoji/closed_umbrella.png differ
diff --git a/app/assets/images/emoji/cloud.png b/app/assets/images/emoji/cloud.png
new file mode 100755
index 00000000..b31c08c0
Binary files /dev/null and b/app/assets/images/emoji/cloud.png differ
diff --git a/app/assets/images/emoji/clubs.png b/app/assets/images/emoji/clubs.png
new file mode 100755
index 00000000..bfab5365
Binary files /dev/null and b/app/assets/images/emoji/clubs.png differ
diff --git a/app/assets/images/emoji/cn.png b/app/assets/images/emoji/cn.png
new file mode 100755
index 00000000..b30dcc53
Binary files /dev/null and b/app/assets/images/emoji/cn.png differ
diff --git a/app/assets/images/emoji/cocktail.png b/app/assets/images/emoji/cocktail.png
new file mode 100755
index 00000000..28b45ea5
Binary files /dev/null and b/app/assets/images/emoji/cocktail.png differ
diff --git a/app/assets/images/emoji/coffee.png b/app/assets/images/emoji/coffee.png
new file mode 100755
index 00000000..57e1adcb
Binary files /dev/null and b/app/assets/images/emoji/coffee.png differ
diff --git a/app/assets/images/emoji/cold_sweat.png b/app/assets/images/emoji/cold_sweat.png
new file mode 100755
index 00000000..b9e39bc6
Binary files /dev/null and b/app/assets/images/emoji/cold_sweat.png differ
diff --git a/app/assets/images/emoji/collision.png b/app/assets/images/emoji/collision.png
new file mode 100755
index 00000000..bddeb8f4
Binary files /dev/null and b/app/assets/images/emoji/collision.png differ
diff --git a/app/assets/images/emoji/computer.png b/app/assets/images/emoji/computer.png
new file mode 100755
index 00000000..d4d26876
Binary files /dev/null and b/app/assets/images/emoji/computer.png differ
diff --git a/app/assets/images/emoji/confetti_ball.png b/app/assets/images/emoji/confetti_ball.png
new file mode 100755
index 00000000..bd293e3d
Binary files /dev/null and b/app/assets/images/emoji/confetti_ball.png differ
diff --git a/app/assets/images/emoji/confounded.png b/app/assets/images/emoji/confounded.png
new file mode 100755
index 00000000..762c3766
Binary files /dev/null and b/app/assets/images/emoji/confounded.png differ
diff --git a/app/assets/images/emoji/congratulations.png b/app/assets/images/emoji/congratulations.png
new file mode 100755
index 00000000..dcbb1d22
Binary files /dev/null and b/app/assets/images/emoji/congratulations.png differ
diff --git a/app/assets/images/emoji/construction.png b/app/assets/images/emoji/construction.png
new file mode 100755
index 00000000..523e9f10
Binary files /dev/null and b/app/assets/images/emoji/construction.png differ
diff --git a/app/assets/images/emoji/construction_worker.png b/app/assets/images/emoji/construction_worker.png
new file mode 100755
index 00000000..4d648604
Binary files /dev/null and b/app/assets/images/emoji/construction_worker.png differ
diff --git a/app/assets/images/emoji/convenience_store.png b/app/assets/images/emoji/convenience_store.png
new file mode 100755
index 00000000..671696c2
Binary files /dev/null and b/app/assets/images/emoji/convenience_store.png differ
diff --git a/app/assets/images/emoji/cookie.png b/app/assets/images/emoji/cookie.png
new file mode 100755
index 00000000..653edb25
Binary files /dev/null and b/app/assets/images/emoji/cookie.png differ
diff --git a/app/assets/images/emoji/cool.png b/app/assets/images/emoji/cool.png
new file mode 100755
index 00000000..937dcd79
Binary files /dev/null and b/app/assets/images/emoji/cool.png differ
diff --git a/app/assets/images/emoji/cop.png b/app/assets/images/emoji/cop.png
new file mode 100755
index 00000000..43a5a84f
Binary files /dev/null and b/app/assets/images/emoji/cop.png differ
diff --git a/app/assets/images/emoji/copyright.png b/app/assets/images/emoji/copyright.png
new file mode 100755
index 00000000..38493c33
Binary files /dev/null and b/app/assets/images/emoji/copyright.png differ
diff --git a/app/assets/images/emoji/corn.png b/app/assets/images/emoji/corn.png
new file mode 100755
index 00000000..fe5d8b12
Binary files /dev/null and b/app/assets/images/emoji/corn.png differ
diff --git a/app/assets/images/emoji/couple.png b/app/assets/images/emoji/couple.png
new file mode 100755
index 00000000..9e51f40e
Binary files /dev/null and b/app/assets/images/emoji/couple.png differ
diff --git a/app/assets/images/emoji/couple_with_heart.png b/app/assets/images/emoji/couple_with_heart.png
new file mode 100755
index 00000000..c503f40a
Binary files /dev/null and b/app/assets/images/emoji/couple_with_heart.png differ
diff --git a/app/assets/images/emoji/couplekiss.png b/app/assets/images/emoji/couplekiss.png
new file mode 100755
index 00000000..d0279082
Binary files /dev/null and b/app/assets/images/emoji/couplekiss.png differ
diff --git a/app/assets/images/emoji/cow.png b/app/assets/images/emoji/cow.png
new file mode 100755
index 00000000..12e1ab6c
Binary files /dev/null and b/app/assets/images/emoji/cow.png differ
diff --git a/app/assets/images/emoji/cow2.png b/app/assets/images/emoji/cow2.png
new file mode 100755
index 00000000..594c9215
Binary files /dev/null and b/app/assets/images/emoji/cow2.png differ
diff --git a/app/assets/images/emoji/credit_card.png b/app/assets/images/emoji/credit_card.png
new file mode 100755
index 00000000..be1c1dd3
Binary files /dev/null and b/app/assets/images/emoji/credit_card.png differ
diff --git a/app/assets/images/emoji/crocodile.png b/app/assets/images/emoji/crocodile.png
new file mode 100755
index 00000000..7435d5ab
Binary files /dev/null and b/app/assets/images/emoji/crocodile.png differ
diff --git a/app/assets/images/emoji/crossed_flags.png b/app/assets/images/emoji/crossed_flags.png
new file mode 100755
index 00000000..2397bcd0
Binary files /dev/null and b/app/assets/images/emoji/crossed_flags.png differ
diff --git a/app/assets/images/emoji/crown.png b/app/assets/images/emoji/crown.png
new file mode 100755
index 00000000..39da1d52
Binary files /dev/null and b/app/assets/images/emoji/crown.png differ
diff --git a/app/assets/images/emoji/cry.png b/app/assets/images/emoji/cry.png
new file mode 100755
index 00000000..6d0d9afd
Binary files /dev/null and b/app/assets/images/emoji/cry.png differ
diff --git a/app/assets/images/emoji/crying_cat_face.png b/app/assets/images/emoji/crying_cat_face.png
new file mode 100755
index 00000000..42d4c27c
Binary files /dev/null and b/app/assets/images/emoji/crying_cat_face.png differ
diff --git a/app/assets/images/emoji/crystal_ball.png b/app/assets/images/emoji/crystal_ball.png
new file mode 100755
index 00000000..6d2c6c42
Binary files /dev/null and b/app/assets/images/emoji/crystal_ball.png differ
diff --git a/app/assets/images/emoji/cupid.png b/app/assets/images/emoji/cupid.png
new file mode 100755
index 00000000..49872847
Binary files /dev/null and b/app/assets/images/emoji/cupid.png differ
diff --git a/app/assets/images/emoji/curly_loop.png b/app/assets/images/emoji/curly_loop.png
new file mode 100755
index 00000000..8f051aca
Binary files /dev/null and b/app/assets/images/emoji/curly_loop.png differ
diff --git a/app/assets/images/emoji/currency_exchange.png b/app/assets/images/emoji/currency_exchange.png
new file mode 100755
index 00000000..6ebebe70
Binary files /dev/null and b/app/assets/images/emoji/currency_exchange.png differ
diff --git a/app/assets/images/emoji/curry.png b/app/assets/images/emoji/curry.png
new file mode 100755
index 00000000..7983c706
Binary files /dev/null and b/app/assets/images/emoji/curry.png differ
diff --git a/app/assets/images/emoji/custard.png b/app/assets/images/emoji/custard.png
new file mode 100755
index 00000000..9f843b4c
Binary files /dev/null and b/app/assets/images/emoji/custard.png differ
diff --git a/app/assets/images/emoji/customs.png b/app/assets/images/emoji/customs.png
new file mode 100755
index 00000000..92691e31
Binary files /dev/null and b/app/assets/images/emoji/customs.png differ
diff --git a/app/assets/images/emoji/cyclone.png b/app/assets/images/emoji/cyclone.png
new file mode 100755
index 00000000..5fd2e451
Binary files /dev/null and b/app/assets/images/emoji/cyclone.png differ
diff --git a/app/assets/images/emoji/dancer.png b/app/assets/images/emoji/dancer.png
new file mode 100755
index 00000000..6885a0bc
Binary files /dev/null and b/app/assets/images/emoji/dancer.png differ
diff --git a/app/assets/images/emoji/dancers.png b/app/assets/images/emoji/dancers.png
new file mode 100755
index 00000000..2dfb451a
Binary files /dev/null and b/app/assets/images/emoji/dancers.png differ
diff --git a/app/assets/images/emoji/dango.png b/app/assets/images/emoji/dango.png
new file mode 100755
index 00000000..2d042aeb
Binary files /dev/null and b/app/assets/images/emoji/dango.png differ
diff --git a/app/assets/images/emoji/dart.png b/app/assets/images/emoji/dart.png
new file mode 100755
index 00000000..0438fe54
Binary files /dev/null and b/app/assets/images/emoji/dart.png differ
diff --git a/app/assets/images/emoji/dash.png b/app/assets/images/emoji/dash.png
new file mode 100755
index 00000000..dc2c0a8f
Binary files /dev/null and b/app/assets/images/emoji/dash.png differ
diff --git a/app/assets/images/emoji/date.png b/app/assets/images/emoji/date.png
new file mode 100755
index 00000000..6ad2efa5
Binary files /dev/null and b/app/assets/images/emoji/date.png differ
diff --git a/app/assets/images/emoji/de.png b/app/assets/images/emoji/de.png
new file mode 100755
index 00000000..16a28548
Binary files /dev/null and b/app/assets/images/emoji/de.png differ
diff --git a/app/assets/images/emoji/deciduous_tree.png b/app/assets/images/emoji/deciduous_tree.png
new file mode 100755
index 00000000..9bb16bdf
Binary files /dev/null and b/app/assets/images/emoji/deciduous_tree.png differ
diff --git a/app/assets/images/emoji/department_store.png b/app/assets/images/emoji/department_store.png
new file mode 100755
index 00000000..68d959c5
Binary files /dev/null and b/app/assets/images/emoji/department_store.png differ
diff --git a/app/assets/images/emoji/diamond_shape_with_a_dot_inside.png b/app/assets/images/emoji/diamond_shape_with_a_dot_inside.png
new file mode 100755
index 00000000..dfd1098b
Binary files /dev/null and b/app/assets/images/emoji/diamond_shape_with_a_dot_inside.png differ
diff --git a/app/assets/images/emoji/diamonds.png b/app/assets/images/emoji/diamonds.png
new file mode 100755
index 00000000..fe082775
Binary files /dev/null and b/app/assets/images/emoji/diamonds.png differ
diff --git a/app/assets/images/emoji/disappointed.png b/app/assets/images/emoji/disappointed.png
new file mode 100755
index 00000000..82552008
Binary files /dev/null and b/app/assets/images/emoji/disappointed.png differ
diff --git a/app/assets/images/emoji/dizzy.png b/app/assets/images/emoji/dizzy.png
new file mode 100755
index 00000000..55213d2d
Binary files /dev/null and b/app/assets/images/emoji/dizzy.png differ
diff --git a/app/assets/images/emoji/dizzy_face.png b/app/assets/images/emoji/dizzy_face.png
new file mode 100755
index 00000000..8001d6ff
Binary files /dev/null and b/app/assets/images/emoji/dizzy_face.png differ
diff --git a/app/assets/images/emoji/do_not_litter.png b/app/assets/images/emoji/do_not_litter.png
new file mode 100755
index 00000000..38c7ae7a
Binary files /dev/null and b/app/assets/images/emoji/do_not_litter.png differ
diff --git a/app/assets/images/emoji/dog.png b/app/assets/images/emoji/dog.png
new file mode 100755
index 00000000..389a02bf
Binary files /dev/null and b/app/assets/images/emoji/dog.png differ
diff --git a/app/assets/images/emoji/dog2.png b/app/assets/images/emoji/dog2.png
new file mode 100755
index 00000000..c7f6a24a
Binary files /dev/null and b/app/assets/images/emoji/dog2.png differ
diff --git a/app/assets/images/emoji/dollar.png b/app/assets/images/emoji/dollar.png
new file mode 100755
index 00000000..63de8849
Binary files /dev/null and b/app/assets/images/emoji/dollar.png differ
diff --git a/app/assets/images/emoji/dolls.png b/app/assets/images/emoji/dolls.png
new file mode 100755
index 00000000..47ce3390
Binary files /dev/null and b/app/assets/images/emoji/dolls.png differ
diff --git a/app/assets/images/emoji/dolphin.png b/app/assets/images/emoji/dolphin.png
new file mode 100755
index 00000000..9326077a
Binary files /dev/null and b/app/assets/images/emoji/dolphin.png differ
diff --git a/app/assets/images/emoji/door.png b/app/assets/images/emoji/door.png
new file mode 100755
index 00000000..83c819ae
Binary files /dev/null and b/app/assets/images/emoji/door.png differ
diff --git a/app/assets/images/emoji/doughnut.png b/app/assets/images/emoji/doughnut.png
new file mode 100755
index 00000000..ccf86912
Binary files /dev/null and b/app/assets/images/emoji/doughnut.png differ
diff --git a/app/assets/images/emoji/dragon.png b/app/assets/images/emoji/dragon.png
new file mode 100755
index 00000000..e399d60e
Binary files /dev/null and b/app/assets/images/emoji/dragon.png differ
diff --git a/app/assets/images/emoji/dragon_face.png b/app/assets/images/emoji/dragon_face.png
new file mode 100755
index 00000000..e5e556bd
Binary files /dev/null and b/app/assets/images/emoji/dragon_face.png differ
diff --git a/app/assets/images/emoji/dress.png b/app/assets/images/emoji/dress.png
new file mode 100755
index 00000000..6434e2e2
Binary files /dev/null and b/app/assets/images/emoji/dress.png differ
diff --git a/app/assets/images/emoji/dromedary_camel.png b/app/assets/images/emoji/dromedary_camel.png
new file mode 100755
index 00000000..c8c7b9ff
Binary files /dev/null and b/app/assets/images/emoji/dromedary_camel.png differ
diff --git a/app/assets/images/emoji/droplet.png b/app/assets/images/emoji/droplet.png
new file mode 100755
index 00000000..9eff4633
Binary files /dev/null and b/app/assets/images/emoji/droplet.png differ
diff --git a/app/assets/images/emoji/dvd.png b/app/assets/images/emoji/dvd.png
new file mode 100755
index 00000000..363c83d0
Binary files /dev/null and b/app/assets/images/emoji/dvd.png differ
diff --git a/app/assets/images/emoji/e-mail.png b/app/assets/images/emoji/e-mail.png
new file mode 100755
index 00000000..176a8e1e
Binary files /dev/null and b/app/assets/images/emoji/e-mail.png differ
diff --git a/app/assets/images/emoji/ear.png b/app/assets/images/emoji/ear.png
new file mode 100755
index 00000000..2bbbf10c
Binary files /dev/null and b/app/assets/images/emoji/ear.png differ
diff --git a/app/assets/images/emoji/ear_of_rice.png b/app/assets/images/emoji/ear_of_rice.png
new file mode 100755
index 00000000..a9bba5c2
Binary files /dev/null and b/app/assets/images/emoji/ear_of_rice.png differ
diff --git a/app/assets/images/emoji/earth_africa.png b/app/assets/images/emoji/earth_africa.png
new file mode 100755
index 00000000..44ce5ecb
Binary files /dev/null and b/app/assets/images/emoji/earth_africa.png differ
diff --git a/app/assets/images/emoji/earth_americas.png b/app/assets/images/emoji/earth_americas.png
new file mode 100755
index 00000000..97d71767
Binary files /dev/null and b/app/assets/images/emoji/earth_americas.png differ
diff --git a/app/assets/images/emoji/earth_asia.png b/app/assets/images/emoji/earth_asia.png
new file mode 100755
index 00000000..95ec357c
Binary files /dev/null and b/app/assets/images/emoji/earth_asia.png differ
diff --git a/app/assets/images/emoji/egg.png b/app/assets/images/emoji/egg.png
new file mode 100755
index 00000000..c3de6ae4
Binary files /dev/null and b/app/assets/images/emoji/egg.png differ
diff --git a/app/assets/images/emoji/eggplant.png b/app/assets/images/emoji/eggplant.png
new file mode 100755
index 00000000..66f25fce
Binary files /dev/null and b/app/assets/images/emoji/eggplant.png differ
diff --git a/app/assets/images/emoji/eight.png b/app/assets/images/emoji/eight.png
new file mode 100755
index 00000000..7bdb4223
Binary files /dev/null and b/app/assets/images/emoji/eight.png differ
diff --git a/app/assets/images/emoji/eight_pointed_black_star.png b/app/assets/images/emoji/eight_pointed_black_star.png
new file mode 100755
index 00000000..6ddaa21f
Binary files /dev/null and b/app/assets/images/emoji/eight_pointed_black_star.png differ
diff --git a/app/assets/images/emoji/eight_spoked_asterisk.png b/app/assets/images/emoji/eight_spoked_asterisk.png
new file mode 100755
index 00000000..946a2033
Binary files /dev/null and b/app/assets/images/emoji/eight_spoked_asterisk.png differ
diff --git a/app/assets/images/emoji/electric_plug.png b/app/assets/images/emoji/electric_plug.png
new file mode 100755
index 00000000..7a3d6cee
Binary files /dev/null and b/app/assets/images/emoji/electric_plug.png differ
diff --git a/app/assets/images/emoji/elephant.png b/app/assets/images/emoji/elephant.png
new file mode 100755
index 00000000..5ca04570
Binary files /dev/null and b/app/assets/images/emoji/elephant.png differ
diff --git a/app/assets/images/emoji/email.png b/app/assets/images/emoji/email.png
new file mode 100755
index 00000000..0e01fd5f
Binary files /dev/null and b/app/assets/images/emoji/email.png differ
diff --git a/app/assets/images/emoji/end.png b/app/assets/images/emoji/end.png
new file mode 100755
index 00000000..edb0bda2
Binary files /dev/null and b/app/assets/images/emoji/end.png differ
diff --git a/app/assets/images/emoji/envelope.png b/app/assets/images/emoji/envelope.png
new file mode 100755
index 00000000..3631861b
Binary files /dev/null and b/app/assets/images/emoji/envelope.png differ
diff --git a/app/assets/images/emoji/es.png b/app/assets/images/emoji/es.png
new file mode 100755
index 00000000..71b30bff
Binary files /dev/null and b/app/assets/images/emoji/es.png differ
diff --git a/app/assets/images/emoji/euro.png b/app/assets/images/emoji/euro.png
new file mode 100755
index 00000000..1c5904b7
Binary files /dev/null and b/app/assets/images/emoji/euro.png differ
diff --git a/app/assets/images/emoji/european_castle.png b/app/assets/images/emoji/european_castle.png
new file mode 100755
index 00000000..8229b8a8
Binary files /dev/null and b/app/assets/images/emoji/european_castle.png differ
diff --git a/app/assets/images/emoji/european_post_office.png b/app/assets/images/emoji/european_post_office.png
new file mode 100755
index 00000000..0f65b145
Binary files /dev/null and b/app/assets/images/emoji/european_post_office.png differ
diff --git a/app/assets/images/emoji/evergreen_tree.png b/app/assets/images/emoji/evergreen_tree.png
new file mode 100755
index 00000000..ae8ad103
Binary files /dev/null and b/app/assets/images/emoji/evergreen_tree.png differ
diff --git a/app/assets/images/emoji/exclamation.png b/app/assets/images/emoji/exclamation.png
new file mode 100755
index 00000000..77bbdeab
Binary files /dev/null and b/app/assets/images/emoji/exclamation.png differ
diff --git a/app/assets/images/emoji/eyeglasses.png b/app/assets/images/emoji/eyeglasses.png
new file mode 100755
index 00000000..a3cf75a2
Binary files /dev/null and b/app/assets/images/emoji/eyeglasses.png differ
diff --git a/app/assets/images/emoji/eyes.png b/app/assets/images/emoji/eyes.png
new file mode 100755
index 00000000..dc2216f6
Binary files /dev/null and b/app/assets/images/emoji/eyes.png differ
diff --git a/app/assets/images/emoji/facepunch.png b/app/assets/images/emoji/facepunch.png
new file mode 100755
index 00000000..2d41fd37
Binary files /dev/null and b/app/assets/images/emoji/facepunch.png differ
diff --git a/app/assets/images/emoji/factory.png b/app/assets/images/emoji/factory.png
new file mode 100755
index 00000000..64046347
Binary files /dev/null and b/app/assets/images/emoji/factory.png differ
diff --git a/app/assets/images/emoji/fallen_leaf.png b/app/assets/images/emoji/fallen_leaf.png
new file mode 100755
index 00000000..d49f9c17
Binary files /dev/null and b/app/assets/images/emoji/fallen_leaf.png differ
diff --git a/app/assets/images/emoji/family.png b/app/assets/images/emoji/family.png
new file mode 100755
index 00000000..b4b365f3
Binary files /dev/null and b/app/assets/images/emoji/family.png differ
diff --git a/app/assets/images/emoji/fast_forward.png b/app/assets/images/emoji/fast_forward.png
new file mode 100755
index 00000000..8830e146
Binary files /dev/null and b/app/assets/images/emoji/fast_forward.png differ
diff --git a/app/assets/images/emoji/fax.png b/app/assets/images/emoji/fax.png
new file mode 100755
index 00000000..62be2c95
Binary files /dev/null and b/app/assets/images/emoji/fax.png differ
diff --git a/app/assets/images/emoji/fearful.png b/app/assets/images/emoji/fearful.png
new file mode 100755
index 00000000..513fce47
Binary files /dev/null and b/app/assets/images/emoji/fearful.png differ
diff --git a/app/assets/images/emoji/feelsgood.png b/app/assets/images/emoji/feelsgood.png
new file mode 100755
index 00000000..361f969b
Binary files /dev/null and b/app/assets/images/emoji/feelsgood.png differ
diff --git a/app/assets/images/emoji/feet.png b/app/assets/images/emoji/feet.png
new file mode 100755
index 00000000..1b0147b1
Binary files /dev/null and b/app/assets/images/emoji/feet.png differ
diff --git a/app/assets/images/emoji/ferris_wheel.png b/app/assets/images/emoji/ferris_wheel.png
new file mode 100755
index 00000000..54a1dcfa
Binary files /dev/null and b/app/assets/images/emoji/ferris_wheel.png differ
diff --git a/app/assets/images/emoji/file_folder.png b/app/assets/images/emoji/file_folder.png
new file mode 100755
index 00000000..4d8bebf8
Binary files /dev/null and b/app/assets/images/emoji/file_folder.png differ
diff --git a/app/assets/images/emoji/finnadie.png b/app/assets/images/emoji/finnadie.png
new file mode 100755
index 00000000..bfc5a0d9
Binary files /dev/null and b/app/assets/images/emoji/finnadie.png differ
diff --git a/app/assets/images/emoji/fire.png b/app/assets/images/emoji/fire.png
new file mode 100755
index 00000000..f2a3149b
Binary files /dev/null and b/app/assets/images/emoji/fire.png differ
diff --git a/app/assets/images/emoji/fire_engine.png b/app/assets/images/emoji/fire_engine.png
new file mode 100755
index 00000000..9e6c59c9
Binary files /dev/null and b/app/assets/images/emoji/fire_engine.png differ
diff --git a/app/assets/images/emoji/fireworks.png b/app/assets/images/emoji/fireworks.png
new file mode 100755
index 00000000..b4eccd57
Binary files /dev/null and b/app/assets/images/emoji/fireworks.png differ
diff --git a/app/assets/images/emoji/first_quarter_moon.png b/app/assets/images/emoji/first_quarter_moon.png
new file mode 100755
index 00000000..f38c2369
Binary files /dev/null and b/app/assets/images/emoji/first_quarter_moon.png differ
diff --git a/app/assets/images/emoji/first_quarter_moon_with_face.png b/app/assets/images/emoji/first_quarter_moon_with_face.png
new file mode 100755
index 00000000..85ae2ce7
Binary files /dev/null and b/app/assets/images/emoji/first_quarter_moon_with_face.png differ
diff --git a/app/assets/images/emoji/fish.png b/app/assets/images/emoji/fish.png
new file mode 100755
index 00000000..90bdda2c
Binary files /dev/null and b/app/assets/images/emoji/fish.png differ
diff --git a/app/assets/images/emoji/fish_cake.png b/app/assets/images/emoji/fish_cake.png
new file mode 100755
index 00000000..a8f22614
Binary files /dev/null and b/app/assets/images/emoji/fish_cake.png differ
diff --git a/app/assets/images/emoji/fishing_pole_and_fish.png b/app/assets/images/emoji/fishing_pole_and_fish.png
new file mode 100755
index 00000000..d84609c3
Binary files /dev/null and b/app/assets/images/emoji/fishing_pole_and_fish.png differ
diff --git a/app/assets/images/emoji/fist.png b/app/assets/images/emoji/fist.png
new file mode 100755
index 00000000..ecc8874c
Binary files /dev/null and b/app/assets/images/emoji/fist.png differ
diff --git a/app/assets/images/emoji/five.png b/app/assets/images/emoji/five.png
new file mode 100755
index 00000000..794321aa
Binary files /dev/null and b/app/assets/images/emoji/five.png differ
diff --git a/app/assets/images/emoji/flags.png b/app/assets/images/emoji/flags.png
new file mode 100755
index 00000000..540164e8
Binary files /dev/null and b/app/assets/images/emoji/flags.png differ
diff --git a/app/assets/images/emoji/flashlight.png b/app/assets/images/emoji/flashlight.png
new file mode 100755
index 00000000..215940aa
Binary files /dev/null and b/app/assets/images/emoji/flashlight.png differ
diff --git a/app/assets/images/emoji/floppy_disk.png b/app/assets/images/emoji/floppy_disk.png
new file mode 100755
index 00000000..4ad56315
Binary files /dev/null and b/app/assets/images/emoji/floppy_disk.png differ
diff --git a/app/assets/images/emoji/flower_playing_cards.png b/app/assets/images/emoji/flower_playing_cards.png
new file mode 100755
index 00000000..cc46a6a1
Binary files /dev/null and b/app/assets/images/emoji/flower_playing_cards.png differ
diff --git a/app/assets/images/emoji/flushed.png b/app/assets/images/emoji/flushed.png
new file mode 100755
index 00000000..74b78c9c
Binary files /dev/null and b/app/assets/images/emoji/flushed.png differ
diff --git a/app/assets/images/emoji/foggy.png b/app/assets/images/emoji/foggy.png
new file mode 100755
index 00000000..3c7b8b04
Binary files /dev/null and b/app/assets/images/emoji/foggy.png differ
diff --git a/app/assets/images/emoji/football.png b/app/assets/images/emoji/football.png
new file mode 100755
index 00000000..0e4e168f
Binary files /dev/null and b/app/assets/images/emoji/football.png differ
diff --git a/app/assets/images/emoji/fork_and_knife.png b/app/assets/images/emoji/fork_and_knife.png
new file mode 100755
index 00000000..8ba4bc65
Binary files /dev/null and b/app/assets/images/emoji/fork_and_knife.png differ
diff --git a/app/assets/images/emoji/fountain.png b/app/assets/images/emoji/fountain.png
new file mode 100755
index 00000000..da126e64
Binary files /dev/null and b/app/assets/images/emoji/fountain.png differ
diff --git a/app/assets/images/emoji/four.png b/app/assets/images/emoji/four.png
new file mode 100755
index 00000000..14782ba2
Binary files /dev/null and b/app/assets/images/emoji/four.png differ
diff --git a/app/assets/images/emoji/four_leaf_clover.png b/app/assets/images/emoji/four_leaf_clover.png
new file mode 100755
index 00000000..f2014bea
Binary files /dev/null and b/app/assets/images/emoji/four_leaf_clover.png differ
diff --git a/app/assets/images/emoji/fr.png b/app/assets/images/emoji/fr.png
new file mode 100755
index 00000000..6311c911
Binary files /dev/null and b/app/assets/images/emoji/fr.png differ
diff --git a/app/assets/images/emoji/free.png b/app/assets/images/emoji/free.png
new file mode 100755
index 00000000..c886cf24
Binary files /dev/null and b/app/assets/images/emoji/free.png differ
diff --git a/app/assets/images/emoji/fried_shrimp.png b/app/assets/images/emoji/fried_shrimp.png
new file mode 100755
index 00000000..c8c284bf
Binary files /dev/null and b/app/assets/images/emoji/fried_shrimp.png differ
diff --git a/app/assets/images/emoji/fries.png b/app/assets/images/emoji/fries.png
new file mode 100755
index 00000000..cfef6696
Binary files /dev/null and b/app/assets/images/emoji/fries.png differ
diff --git a/app/assets/images/emoji/frog.png b/app/assets/images/emoji/frog.png
new file mode 100755
index 00000000..cfe11b18
Binary files /dev/null and b/app/assets/images/emoji/frog.png differ
diff --git a/app/assets/images/emoji/fuelpump.png b/app/assets/images/emoji/fuelpump.png
new file mode 100755
index 00000000..54c29aeb
Binary files /dev/null and b/app/assets/images/emoji/fuelpump.png differ
diff --git a/app/assets/images/emoji/full_moon.png b/app/assets/images/emoji/full_moon.png
new file mode 100755
index 00000000..8ff657a2
Binary files /dev/null and b/app/assets/images/emoji/full_moon.png differ
diff --git a/app/assets/images/emoji/full_moon_with_face.png b/app/assets/images/emoji/full_moon_with_face.png
new file mode 100755
index 00000000..94395a40
Binary files /dev/null and b/app/assets/images/emoji/full_moon_with_face.png differ
diff --git a/app/assets/images/emoji/game_die.png b/app/assets/images/emoji/game_die.png
new file mode 100755
index 00000000..4136e78e
Binary files /dev/null and b/app/assets/images/emoji/game_die.png differ
diff --git a/app/assets/images/emoji/gb.png b/app/assets/images/emoji/gb.png
new file mode 100755
index 00000000..2a62c7a0
Binary files /dev/null and b/app/assets/images/emoji/gb.png differ
diff --git a/app/assets/images/emoji/gem.png b/app/assets/images/emoji/gem.png
new file mode 100755
index 00000000..8a5d8dad
Binary files /dev/null and b/app/assets/images/emoji/gem.png differ
diff --git a/app/assets/images/emoji/gemini.png b/app/assets/images/emoji/gemini.png
new file mode 100755
index 00000000..d926f6e8
Binary files /dev/null and b/app/assets/images/emoji/gemini.png differ
diff --git a/app/assets/images/emoji/ghost.png b/app/assets/images/emoji/ghost.png
new file mode 100755
index 00000000..671dd0c9
Binary files /dev/null and b/app/assets/images/emoji/ghost.png differ
diff --git a/app/assets/images/emoji/gift.png b/app/assets/images/emoji/gift.png
new file mode 100755
index 00000000..552cfdc2
Binary files /dev/null and b/app/assets/images/emoji/gift.png differ
diff --git a/app/assets/images/emoji/gift_heart.png b/app/assets/images/emoji/gift_heart.png
new file mode 100755
index 00000000..f31c26a3
Binary files /dev/null and b/app/assets/images/emoji/gift_heart.png differ
diff --git a/app/assets/images/emoji/girl.png b/app/assets/images/emoji/girl.png
new file mode 100755
index 00000000..ea412694
Binary files /dev/null and b/app/assets/images/emoji/girl.png differ
diff --git a/app/assets/images/emoji/globe_with_meridians.png b/app/assets/images/emoji/globe_with_meridians.png
new file mode 100755
index 00000000..b1986466
Binary files /dev/null and b/app/assets/images/emoji/globe_with_meridians.png differ
diff --git a/app/assets/images/emoji/goat.png b/app/assets/images/emoji/goat.png
new file mode 100755
index 00000000..4be9cf30
Binary files /dev/null and b/app/assets/images/emoji/goat.png differ
diff --git a/app/assets/images/emoji/goberserk.png b/app/assets/images/emoji/goberserk.png
new file mode 100755
index 00000000..59a742aa
Binary files /dev/null and b/app/assets/images/emoji/goberserk.png differ
diff --git a/app/assets/images/emoji/godmode.png b/app/assets/images/emoji/godmode.png
new file mode 100755
index 00000000..7e75ab20
Binary files /dev/null and b/app/assets/images/emoji/godmode.png differ
diff --git a/app/assets/images/emoji/golf.png b/app/assets/images/emoji/golf.png
new file mode 100755
index 00000000..cba2116a
Binary files /dev/null and b/app/assets/images/emoji/golf.png differ
diff --git a/app/assets/images/emoji/grapes.png b/app/assets/images/emoji/grapes.png
new file mode 100755
index 00000000..0f9f007a
Binary files /dev/null and b/app/assets/images/emoji/grapes.png differ
diff --git a/app/assets/images/emoji/green_apple.png b/app/assets/images/emoji/green_apple.png
new file mode 100755
index 00000000..337205cd
Binary files /dev/null and b/app/assets/images/emoji/green_apple.png differ
diff --git a/app/assets/images/emoji/green_book.png b/app/assets/images/emoji/green_book.png
new file mode 100755
index 00000000..e86651e5
Binary files /dev/null and b/app/assets/images/emoji/green_book.png differ
diff --git a/app/assets/images/emoji/green_heart.png b/app/assets/images/emoji/green_heart.png
new file mode 100755
index 00000000..7289cb81
Binary files /dev/null and b/app/assets/images/emoji/green_heart.png differ
diff --git a/app/assets/images/emoji/grey_exclamation.png b/app/assets/images/emoji/grey_exclamation.png
new file mode 100755
index 00000000..a50d265e
Binary files /dev/null and b/app/assets/images/emoji/grey_exclamation.png differ
diff --git a/app/assets/images/emoji/grey_question.png b/app/assets/images/emoji/grey_question.png
new file mode 100755
index 00000000..fb97ba75
Binary files /dev/null and b/app/assets/images/emoji/grey_question.png differ
diff --git a/app/assets/images/emoji/grin.png b/app/assets/images/emoji/grin.png
new file mode 100755
index 00000000..591cfcef
Binary files /dev/null and b/app/assets/images/emoji/grin.png differ
diff --git a/app/assets/images/emoji/guardsman.png b/app/assets/images/emoji/guardsman.png
new file mode 100755
index 00000000..b67b335d
Binary files /dev/null and b/app/assets/images/emoji/guardsman.png differ
diff --git a/app/assets/images/emoji/guitar.png b/app/assets/images/emoji/guitar.png
new file mode 100755
index 00000000..2b7fa43c
Binary files /dev/null and b/app/assets/images/emoji/guitar.png differ
diff --git a/app/assets/images/emoji/gun.png b/app/assets/images/emoji/gun.png
new file mode 100755
index 00000000..c49dc52c
Binary files /dev/null and b/app/assets/images/emoji/gun.png differ
diff --git a/app/assets/images/emoji/haircut.png b/app/assets/images/emoji/haircut.png
new file mode 100755
index 00000000..902d273f
Binary files /dev/null and b/app/assets/images/emoji/haircut.png differ
diff --git a/app/assets/images/emoji/hamburger.png b/app/assets/images/emoji/hamburger.png
new file mode 100755
index 00000000..9f1a3fdf
Binary files /dev/null and b/app/assets/images/emoji/hamburger.png differ
diff --git a/app/assets/images/emoji/hammer.png b/app/assets/images/emoji/hammer.png
new file mode 100755
index 00000000..482b1c74
Binary files /dev/null and b/app/assets/images/emoji/hammer.png differ
diff --git a/app/assets/images/emoji/hamster.png b/app/assets/images/emoji/hamster.png
new file mode 100755
index 00000000..addfd2e6
Binary files /dev/null and b/app/assets/images/emoji/hamster.png differ
diff --git a/app/assets/images/emoji/hand.png b/app/assets/images/emoji/hand.png
new file mode 100755
index 00000000..5e45c25a
Binary files /dev/null and b/app/assets/images/emoji/hand.png differ
diff --git a/app/assets/images/emoji/handbag.png b/app/assets/images/emoji/handbag.png
new file mode 100755
index 00000000..d7adf04d
Binary files /dev/null and b/app/assets/images/emoji/handbag.png differ
diff --git a/app/assets/images/emoji/hankey.png b/app/assets/images/emoji/hankey.png
new file mode 100755
index 00000000..73a4dc84
Binary files /dev/null and b/app/assets/images/emoji/hankey.png differ
diff --git a/app/assets/images/emoji/hash.png b/app/assets/images/emoji/hash.png
new file mode 100755
index 00000000..6765d7d3
Binary files /dev/null and b/app/assets/images/emoji/hash.png differ
diff --git a/app/assets/images/emoji/hatched_chick.png b/app/assets/images/emoji/hatched_chick.png
new file mode 100755
index 00000000..39c25bc7
Binary files /dev/null and b/app/assets/images/emoji/hatched_chick.png differ
diff --git a/app/assets/images/emoji/hatching_chick.png b/app/assets/images/emoji/hatching_chick.png
new file mode 100755
index 00000000..005a5551
Binary files /dev/null and b/app/assets/images/emoji/hatching_chick.png differ
diff --git a/app/assets/images/emoji/headphones.png b/app/assets/images/emoji/headphones.png
new file mode 100755
index 00000000..ad83000e
Binary files /dev/null and b/app/assets/images/emoji/headphones.png differ
diff --git a/app/assets/images/emoji/hear_no_evil.png b/app/assets/images/emoji/hear_no_evil.png
new file mode 100755
index 00000000..f97a1f9a
Binary files /dev/null and b/app/assets/images/emoji/hear_no_evil.png differ
diff --git a/app/assets/images/emoji/heart.png b/app/assets/images/emoji/heart.png
new file mode 100755
index 00000000..7d7790ce
Binary files /dev/null and b/app/assets/images/emoji/heart.png differ
diff --git a/app/assets/images/emoji/heart_decoration.png b/app/assets/images/emoji/heart_decoration.png
new file mode 100755
index 00000000..b8be44db
Binary files /dev/null and b/app/assets/images/emoji/heart_decoration.png differ
diff --git a/app/assets/images/emoji/heart_eyes.png b/app/assets/images/emoji/heart_eyes.png
new file mode 100755
index 00000000..0e579427
Binary files /dev/null and b/app/assets/images/emoji/heart_eyes.png differ
diff --git a/app/assets/images/emoji/heart_eyes_cat.png b/app/assets/images/emoji/heart_eyes_cat.png
new file mode 100755
index 00000000..eeba240e
Binary files /dev/null and b/app/assets/images/emoji/heart_eyes_cat.png differ
diff --git a/app/assets/images/emoji/heartbeat.png b/app/assets/images/emoji/heartbeat.png
new file mode 100755
index 00000000..b6628f6f
Binary files /dev/null and b/app/assets/images/emoji/heartbeat.png differ
diff --git a/app/assets/images/emoji/heartpulse.png b/app/assets/images/emoji/heartpulse.png
new file mode 100755
index 00000000..a7491cbe
Binary files /dev/null and b/app/assets/images/emoji/heartpulse.png differ
diff --git a/app/assets/images/emoji/hearts.png b/app/assets/images/emoji/hearts.png
new file mode 100755
index 00000000..e8947153
Binary files /dev/null and b/app/assets/images/emoji/hearts.png differ
diff --git a/app/assets/images/emoji/heavy_check_mark.png b/app/assets/images/emoji/heavy_check_mark.png
new file mode 100755
index 00000000..336d2626
Binary files /dev/null and b/app/assets/images/emoji/heavy_check_mark.png differ
diff --git a/app/assets/images/emoji/heavy_division_sign.png b/app/assets/images/emoji/heavy_division_sign.png
new file mode 100755
index 00000000..ac757a23
Binary files /dev/null and b/app/assets/images/emoji/heavy_division_sign.png differ
diff --git a/app/assets/images/emoji/heavy_dollar_sign.png b/app/assets/images/emoji/heavy_dollar_sign.png
new file mode 100755
index 00000000..361e26ae
Binary files /dev/null and b/app/assets/images/emoji/heavy_dollar_sign.png differ
diff --git a/app/assets/images/emoji/heavy_exclamation_mark.png b/app/assets/images/emoji/heavy_exclamation_mark.png
new file mode 100755
index 00000000..4c560f5e
Binary files /dev/null and b/app/assets/images/emoji/heavy_exclamation_mark.png differ
diff --git a/app/assets/images/emoji/heavy_minus_sign.png b/app/assets/images/emoji/heavy_minus_sign.png
new file mode 100755
index 00000000..b8d3d82f
Binary files /dev/null and b/app/assets/images/emoji/heavy_minus_sign.png differ
diff --git a/app/assets/images/emoji/heavy_multiplication_x.png b/app/assets/images/emoji/heavy_multiplication_x.png
new file mode 100755
index 00000000..13d66607
Binary files /dev/null and b/app/assets/images/emoji/heavy_multiplication_x.png differ
diff --git a/app/assets/images/emoji/heavy_plus_sign.png b/app/assets/images/emoji/heavy_plus_sign.png
new file mode 100755
index 00000000..61595387
Binary files /dev/null and b/app/assets/images/emoji/heavy_plus_sign.png differ
diff --git a/app/assets/images/emoji/helicopter.png b/app/assets/images/emoji/helicopter.png
new file mode 100755
index 00000000..8e82a0d5
Binary files /dev/null and b/app/assets/images/emoji/helicopter.png differ
diff --git a/app/assets/images/emoji/herb.png b/app/assets/images/emoji/herb.png
new file mode 100755
index 00000000..de1ff1b7
Binary files /dev/null and b/app/assets/images/emoji/herb.png differ
diff --git a/app/assets/images/emoji/hibiscus.png b/app/assets/images/emoji/hibiscus.png
new file mode 100755
index 00000000..9365ae21
Binary files /dev/null and b/app/assets/images/emoji/hibiscus.png differ
diff --git a/app/assets/images/emoji/high_brightness.png b/app/assets/images/emoji/high_brightness.png
new file mode 100755
index 00000000..ba9de7d4
Binary files /dev/null and b/app/assets/images/emoji/high_brightness.png differ
diff --git a/app/assets/images/emoji/high_heel.png b/app/assets/images/emoji/high_heel.png
new file mode 100755
index 00000000..525b6a0d
Binary files /dev/null and b/app/assets/images/emoji/high_heel.png differ
diff --git a/app/assets/images/emoji/hocho.png b/app/assets/images/emoji/hocho.png
new file mode 100755
index 00000000..18eade0a
Binary files /dev/null and b/app/assets/images/emoji/hocho.png differ
diff --git a/app/assets/images/emoji/honey_pot.png b/app/assets/images/emoji/honey_pot.png
new file mode 100755
index 00000000..73278898
Binary files /dev/null and b/app/assets/images/emoji/honey_pot.png differ
diff --git a/app/assets/images/emoji/honeybee.png b/app/assets/images/emoji/honeybee.png
new file mode 100755
index 00000000..f5373395
Binary files /dev/null and b/app/assets/images/emoji/honeybee.png differ
diff --git a/app/assets/images/emoji/horse.png b/app/assets/images/emoji/horse.png
new file mode 100755
index 00000000..78d580ad
Binary files /dev/null and b/app/assets/images/emoji/horse.png differ
diff --git a/app/assets/images/emoji/horse_racing.png b/app/assets/images/emoji/horse_racing.png
new file mode 100755
index 00000000..e3bbaec1
Binary files /dev/null and b/app/assets/images/emoji/horse_racing.png differ
diff --git a/app/assets/images/emoji/hospital.png b/app/assets/images/emoji/hospital.png
new file mode 100755
index 00000000..c05c4937
Binary files /dev/null and b/app/assets/images/emoji/hospital.png differ
diff --git a/app/assets/images/emoji/hotel.png b/app/assets/images/emoji/hotel.png
new file mode 100755
index 00000000..d29f276a
Binary files /dev/null and b/app/assets/images/emoji/hotel.png differ
diff --git a/app/assets/images/emoji/hotsprings.png b/app/assets/images/emoji/hotsprings.png
new file mode 100755
index 00000000..a0bc9d75
Binary files /dev/null and b/app/assets/images/emoji/hotsprings.png differ
diff --git a/app/assets/images/emoji/hourglass.png b/app/assets/images/emoji/hourglass.png
new file mode 100755
index 00000000..405aab41
Binary files /dev/null and b/app/assets/images/emoji/hourglass.png differ
diff --git a/app/assets/images/emoji/house.png b/app/assets/images/emoji/house.png
new file mode 100755
index 00000000..95b9ee09
Binary files /dev/null and b/app/assets/images/emoji/house.png differ
diff --git a/app/assets/images/emoji/hurtrealbad.png b/app/assets/images/emoji/hurtrealbad.png
new file mode 100755
index 00000000..146ef1a6
Binary files /dev/null and b/app/assets/images/emoji/hurtrealbad.png differ
diff --git a/app/assets/images/emoji/ice_cream.png b/app/assets/images/emoji/ice_cream.png
new file mode 100755
index 00000000..190be016
Binary files /dev/null and b/app/assets/images/emoji/ice_cream.png differ
diff --git a/app/assets/images/emoji/icecream.png b/app/assets/images/emoji/icecream.png
new file mode 100755
index 00000000..871ce097
Binary files /dev/null and b/app/assets/images/emoji/icecream.png differ
diff --git a/app/assets/images/emoji/id.png b/app/assets/images/emoji/id.png
new file mode 100755
index 00000000..47437a76
Binary files /dev/null and b/app/assets/images/emoji/id.png differ
diff --git a/app/assets/images/emoji/ideograph_advantage.png b/app/assets/images/emoji/ideograph_advantage.png
new file mode 100755
index 00000000..e79af784
Binary files /dev/null and b/app/assets/images/emoji/ideograph_advantage.png differ
diff --git a/app/assets/images/emoji/imp.png b/app/assets/images/emoji/imp.png
new file mode 100755
index 00000000..5acca337
Binary files /dev/null and b/app/assets/images/emoji/imp.png differ
diff --git a/app/assets/images/emoji/inbox_tray.png b/app/assets/images/emoji/inbox_tray.png
new file mode 100755
index 00000000..e2df0f89
Binary files /dev/null and b/app/assets/images/emoji/inbox_tray.png differ
diff --git a/app/assets/images/emoji/incoming_envelope.png b/app/assets/images/emoji/incoming_envelope.png
new file mode 100755
index 00000000..afc82712
Binary files /dev/null and b/app/assets/images/emoji/incoming_envelope.png differ
diff --git a/app/assets/images/emoji/information_desk_person.png b/app/assets/images/emoji/information_desk_person.png
new file mode 100755
index 00000000..52c0a50a
Binary files /dev/null and b/app/assets/images/emoji/information_desk_person.png differ
diff --git a/app/assets/images/emoji/information_source.png b/app/assets/images/emoji/information_source.png
new file mode 100755
index 00000000..9cb8b09b
Binary files /dev/null and b/app/assets/images/emoji/information_source.png differ
diff --git a/app/assets/images/emoji/innocent.png b/app/assets/images/emoji/innocent.png
new file mode 100755
index 00000000..503b614f
Binary files /dev/null and b/app/assets/images/emoji/innocent.png differ
diff --git a/app/assets/images/emoji/interrobang.png b/app/assets/images/emoji/interrobang.png
new file mode 100755
index 00000000..64304b9f
Binary files /dev/null and b/app/assets/images/emoji/interrobang.png differ
diff --git a/app/assets/images/emoji/iphone.png b/app/assets/images/emoji/iphone.png
new file mode 100755
index 00000000..df007103
Binary files /dev/null and b/app/assets/images/emoji/iphone.png differ
diff --git a/app/assets/images/emoji/it.png b/app/assets/images/emoji/it.png
new file mode 100755
index 00000000..70bc9f32
Binary files /dev/null and b/app/assets/images/emoji/it.png differ
diff --git a/app/assets/images/emoji/izakaya_lantern.png b/app/assets/images/emoji/izakaya_lantern.png
new file mode 100755
index 00000000..18730ad5
Binary files /dev/null and b/app/assets/images/emoji/izakaya_lantern.png differ
diff --git a/app/assets/images/emoji/jack_o_lantern.png b/app/assets/images/emoji/jack_o_lantern.png
new file mode 100755
index 00000000..1f7667ea
Binary files /dev/null and b/app/assets/images/emoji/jack_o_lantern.png differ
diff --git a/app/assets/images/emoji/japan.png b/app/assets/images/emoji/japan.png
new file mode 100755
index 00000000..45932803
Binary files /dev/null and b/app/assets/images/emoji/japan.png differ
diff --git a/app/assets/images/emoji/japanese_castle.png b/app/assets/images/emoji/japanese_castle.png
new file mode 100755
index 00000000..f225ab21
Binary files /dev/null and b/app/assets/images/emoji/japanese_castle.png differ
diff --git a/app/assets/images/emoji/japanese_goblin.png b/app/assets/images/emoji/japanese_goblin.png
new file mode 100755
index 00000000..bd21b187
Binary files /dev/null and b/app/assets/images/emoji/japanese_goblin.png differ
diff --git a/app/assets/images/emoji/japanese_ogre.png b/app/assets/images/emoji/japanese_ogre.png
new file mode 100755
index 00000000..e9f5471c
Binary files /dev/null and b/app/assets/images/emoji/japanese_ogre.png differ
diff --git a/app/assets/images/emoji/jeans.png b/app/assets/images/emoji/jeans.png
new file mode 100755
index 00000000..d721cea5
Binary files /dev/null and b/app/assets/images/emoji/jeans.png differ
diff --git a/app/assets/images/emoji/joy.png b/app/assets/images/emoji/joy.png
new file mode 100755
index 00000000..47df693d
Binary files /dev/null and b/app/assets/images/emoji/joy.png differ
diff --git a/app/assets/images/emoji/joy_cat.png b/app/assets/images/emoji/joy_cat.png
new file mode 100755
index 00000000..6c60cb0e
Binary files /dev/null and b/app/assets/images/emoji/joy_cat.png differ
diff --git a/app/assets/images/emoji/jp.png b/app/assets/images/emoji/jp.png
new file mode 100755
index 00000000..b786efbb
Binary files /dev/null and b/app/assets/images/emoji/jp.png differ
diff --git a/app/assets/images/emoji/key.png b/app/assets/images/emoji/key.png
new file mode 100755
index 00000000..34673213
Binary files /dev/null and b/app/assets/images/emoji/key.png differ
diff --git a/app/assets/images/emoji/keycap_ten.png b/app/assets/images/emoji/keycap_ten.png
new file mode 100755
index 00000000..71dac1c1
Binary files /dev/null and b/app/assets/images/emoji/keycap_ten.png differ
diff --git a/app/assets/images/emoji/kimono.png b/app/assets/images/emoji/kimono.png
new file mode 100755
index 00000000..34ffe137
Binary files /dev/null and b/app/assets/images/emoji/kimono.png differ
diff --git a/app/assets/images/emoji/kiss.png b/app/assets/images/emoji/kiss.png
new file mode 100755
index 00000000..14fd9918
Binary files /dev/null and b/app/assets/images/emoji/kiss.png differ
diff --git a/app/assets/images/emoji/kissing_cat.png b/app/assets/images/emoji/kissing_cat.png
new file mode 100755
index 00000000..adc62fbe
Binary files /dev/null and b/app/assets/images/emoji/kissing_cat.png differ
diff --git a/app/assets/images/emoji/kissing_face.png b/app/assets/images/emoji/kissing_face.png
new file mode 100755
index 00000000..449de197
Binary files /dev/null and b/app/assets/images/emoji/kissing_face.png differ
diff --git a/app/assets/images/emoji/kissing_heart.png b/app/assets/images/emoji/kissing_heart.png
new file mode 100755
index 00000000..af9a80b7
Binary files /dev/null and b/app/assets/images/emoji/kissing_heart.png differ
diff --git a/app/assets/images/emoji/koala.png b/app/assets/images/emoji/koala.png
new file mode 100755
index 00000000..e17bd3cf
Binary files /dev/null and b/app/assets/images/emoji/koala.png differ
diff --git a/app/assets/images/emoji/koko.png b/app/assets/images/emoji/koko.png
new file mode 100755
index 00000000..3bef28c9
Binary files /dev/null and b/app/assets/images/emoji/koko.png differ
diff --git a/app/assets/images/emoji/kr.png b/app/assets/images/emoji/kr.png
new file mode 100755
index 00000000..b4c0c1b6
Binary files /dev/null and b/app/assets/images/emoji/kr.png differ
diff --git a/app/assets/images/emoji/large_blue_circle.png b/app/assets/images/emoji/large_blue_circle.png
new file mode 100755
index 00000000..a5b4ad4a
Binary files /dev/null and b/app/assets/images/emoji/large_blue_circle.png differ
diff --git a/app/assets/images/emoji/large_blue_diamond.png b/app/assets/images/emoji/large_blue_diamond.png
new file mode 100755
index 00000000..f4598ec0
Binary files /dev/null and b/app/assets/images/emoji/large_blue_diamond.png differ
diff --git a/app/assets/images/emoji/large_orange_diamond.png b/app/assets/images/emoji/large_orange_diamond.png
new file mode 100755
index 00000000..46d52e5c
Binary files /dev/null and b/app/assets/images/emoji/large_orange_diamond.png differ
diff --git a/app/assets/images/emoji/last_quarter_moon.png b/app/assets/images/emoji/last_quarter_moon.png
new file mode 100755
index 00000000..355e3c3f
Binary files /dev/null and b/app/assets/images/emoji/last_quarter_moon.png differ
diff --git a/app/assets/images/emoji/last_quarter_moon_with_face.png b/app/assets/images/emoji/last_quarter_moon_with_face.png
new file mode 100755
index 00000000..9ece82df
Binary files /dev/null and b/app/assets/images/emoji/last_quarter_moon_with_face.png differ
diff --git a/app/assets/images/emoji/laughing.png b/app/assets/images/emoji/laughing.png
new file mode 100755
index 00000000..11c91eb2
Binary files /dev/null and b/app/assets/images/emoji/laughing.png differ
diff --git a/app/assets/images/emoji/leaves.png b/app/assets/images/emoji/leaves.png
new file mode 100755
index 00000000..5229e06b
Binary files /dev/null and b/app/assets/images/emoji/leaves.png differ
diff --git a/app/assets/images/emoji/ledger.png b/app/assets/images/emoji/ledger.png
new file mode 100755
index 00000000..e4f72ace
Binary files /dev/null and b/app/assets/images/emoji/ledger.png differ
diff --git a/app/assets/images/emoji/left_luggage.png b/app/assets/images/emoji/left_luggage.png
new file mode 100755
index 00000000..1c08b464
Binary files /dev/null and b/app/assets/images/emoji/left_luggage.png differ
diff --git a/app/assets/images/emoji/left_right_arrow.png b/app/assets/images/emoji/left_right_arrow.png
new file mode 100755
index 00000000..b9fd11c5
Binary files /dev/null and b/app/assets/images/emoji/left_right_arrow.png differ
diff --git a/app/assets/images/emoji/leftwards_arrow_with_hook.png b/app/assets/images/emoji/leftwards_arrow_with_hook.png
new file mode 100755
index 00000000..bc45dfef
Binary files /dev/null and b/app/assets/images/emoji/leftwards_arrow_with_hook.png differ
diff --git a/app/assets/images/emoji/lemon.png b/app/assets/images/emoji/lemon.png
new file mode 100755
index 00000000..9814dc95
Binary files /dev/null and b/app/assets/images/emoji/lemon.png differ
diff --git a/app/assets/images/emoji/leo.png b/app/assets/images/emoji/leo.png
new file mode 100755
index 00000000..e025933b
Binary files /dev/null and b/app/assets/images/emoji/leo.png differ
diff --git a/app/assets/images/emoji/leopard.png b/app/assets/images/emoji/leopard.png
new file mode 100755
index 00000000..8abfc4a2
Binary files /dev/null and b/app/assets/images/emoji/leopard.png differ
diff --git a/app/assets/images/emoji/libra.png b/app/assets/images/emoji/libra.png
new file mode 100755
index 00000000..c9062dd2
Binary files /dev/null and b/app/assets/images/emoji/libra.png differ
diff --git a/app/assets/images/emoji/light_rail.png b/app/assets/images/emoji/light_rail.png
new file mode 100755
index 00000000..bcfe801e
Binary files /dev/null and b/app/assets/images/emoji/light_rail.png differ
diff --git a/app/assets/images/emoji/link.png b/app/assets/images/emoji/link.png
new file mode 100755
index 00000000..ffb8f62c
Binary files /dev/null and b/app/assets/images/emoji/link.png differ
diff --git a/app/assets/images/emoji/lips.png b/app/assets/images/emoji/lips.png
new file mode 100755
index 00000000..826ed110
Binary files /dev/null and b/app/assets/images/emoji/lips.png differ
diff --git a/app/assets/images/emoji/lipstick.png b/app/assets/images/emoji/lipstick.png
new file mode 100755
index 00000000..82f990c5
Binary files /dev/null and b/app/assets/images/emoji/lipstick.png differ
diff --git a/app/assets/images/emoji/lock.png b/app/assets/images/emoji/lock.png
new file mode 100755
index 00000000..4892b023
Binary files /dev/null and b/app/assets/images/emoji/lock.png differ
diff --git a/app/assets/images/emoji/lock_with_ink_pen.png b/app/assets/images/emoji/lock_with_ink_pen.png
new file mode 100755
index 00000000..375e67e8
Binary files /dev/null and b/app/assets/images/emoji/lock_with_ink_pen.png differ
diff --git a/app/assets/images/emoji/lollipop.png b/app/assets/images/emoji/lollipop.png
new file mode 100755
index 00000000..ba55e709
Binary files /dev/null and b/app/assets/images/emoji/lollipop.png differ
diff --git a/app/assets/images/emoji/loop.png b/app/assets/images/emoji/loop.png
new file mode 100755
index 00000000..ef34df3a
Binary files /dev/null and b/app/assets/images/emoji/loop.png differ
diff --git a/app/assets/images/emoji/loudspeaker.png b/app/assets/images/emoji/loudspeaker.png
new file mode 100755
index 00000000..752385e5
Binary files /dev/null and b/app/assets/images/emoji/loudspeaker.png differ
diff --git a/app/assets/images/emoji/love_hotel.png b/app/assets/images/emoji/love_hotel.png
new file mode 100755
index 00000000..44d7db82
Binary files /dev/null and b/app/assets/images/emoji/love_hotel.png differ
diff --git a/app/assets/images/emoji/love_letter.png b/app/assets/images/emoji/love_letter.png
new file mode 100755
index 00000000..e29981f4
Binary files /dev/null and b/app/assets/images/emoji/love_letter.png differ
diff --git a/app/assets/images/emoji/low_brightness.png b/app/assets/images/emoji/low_brightness.png
new file mode 100755
index 00000000..ea15bde4
Binary files /dev/null and b/app/assets/images/emoji/low_brightness.png differ
diff --git a/app/assets/images/emoji/m.png b/app/assets/images/emoji/m.png
new file mode 100755
index 00000000..7424665e
Binary files /dev/null and b/app/assets/images/emoji/m.png differ
diff --git a/app/assets/images/emoji/mag.png b/app/assets/images/emoji/mag.png
new file mode 100755
index 00000000..aa5b1d7c
Binary files /dev/null and b/app/assets/images/emoji/mag.png differ
diff --git a/app/assets/images/emoji/mag_right.png b/app/assets/images/emoji/mag_right.png
new file mode 100755
index 00000000..6e6cf11e
Binary files /dev/null and b/app/assets/images/emoji/mag_right.png differ
diff --git a/app/assets/images/emoji/mahjong.png b/app/assets/images/emoji/mahjong.png
new file mode 100755
index 00000000..f51ce65f
Binary files /dev/null and b/app/assets/images/emoji/mahjong.png differ
diff --git a/app/assets/images/emoji/mailbox.png b/app/assets/images/emoji/mailbox.png
new file mode 100755
index 00000000..8351e707
Binary files /dev/null and b/app/assets/images/emoji/mailbox.png differ
diff --git a/app/assets/images/emoji/mailbox_closed.png b/app/assets/images/emoji/mailbox_closed.png
new file mode 100755
index 00000000..a5982b69
Binary files /dev/null and b/app/assets/images/emoji/mailbox_closed.png differ
diff --git a/app/assets/images/emoji/mailbox_with_mail.png b/app/assets/images/emoji/mailbox_with_mail.png
new file mode 100755
index 00000000..dae34594
Binary files /dev/null and b/app/assets/images/emoji/mailbox_with_mail.png differ
diff --git a/app/assets/images/emoji/mailbox_with_no_mail.png b/app/assets/images/emoji/mailbox_with_no_mail.png
new file mode 100755
index 00000000..59f15c5d
Binary files /dev/null and b/app/assets/images/emoji/mailbox_with_no_mail.png differ
diff --git a/app/assets/images/emoji/man.png b/app/assets/images/emoji/man.png
new file mode 100755
index 00000000..d9bfa26a
Binary files /dev/null and b/app/assets/images/emoji/man.png differ
diff --git a/app/assets/images/emoji/man_with_gua_pi_mao.png b/app/assets/images/emoji/man_with_gua_pi_mao.png
new file mode 100755
index 00000000..7aad74b5
Binary files /dev/null and b/app/assets/images/emoji/man_with_gua_pi_mao.png differ
diff --git a/app/assets/images/emoji/man_with_turban.png b/app/assets/images/emoji/man_with_turban.png
new file mode 100755
index 00000000..036604ca
Binary files /dev/null and b/app/assets/images/emoji/man_with_turban.png differ
diff --git a/app/assets/images/emoji/mans_shoe.png b/app/assets/images/emoji/mans_shoe.png
new file mode 100755
index 00000000..ecba9ba7
Binary files /dev/null and b/app/assets/images/emoji/mans_shoe.png differ
diff --git a/app/assets/images/emoji/maple_leaf.png b/app/assets/images/emoji/maple_leaf.png
new file mode 100755
index 00000000..4e9b4720
Binary files /dev/null and b/app/assets/images/emoji/maple_leaf.png differ
diff --git a/app/assets/images/emoji/mask.png b/app/assets/images/emoji/mask.png
new file mode 100755
index 00000000..05887e99
Binary files /dev/null and b/app/assets/images/emoji/mask.png differ
diff --git a/app/assets/images/emoji/massage.png b/app/assets/images/emoji/massage.png
new file mode 100755
index 00000000..dd30d159
Binary files /dev/null and b/app/assets/images/emoji/massage.png differ
diff --git a/app/assets/images/emoji/meat_on_bone.png b/app/assets/images/emoji/meat_on_bone.png
new file mode 100755
index 00000000..d6b311b6
Binary files /dev/null and b/app/assets/images/emoji/meat_on_bone.png differ
diff --git a/app/assets/images/emoji/mega.png b/app/assets/images/emoji/mega.png
new file mode 100755
index 00000000..022df2f8
Binary files /dev/null and b/app/assets/images/emoji/mega.png differ
diff --git a/app/assets/images/emoji/melon.png b/app/assets/images/emoji/melon.png
new file mode 100755
index 00000000..11c13cbb
Binary files /dev/null and b/app/assets/images/emoji/melon.png differ
diff --git a/app/assets/images/emoji/memo.png b/app/assets/images/emoji/memo.png
new file mode 100755
index 00000000..fc97ddbc
Binary files /dev/null and b/app/assets/images/emoji/memo.png differ
diff --git a/app/assets/images/emoji/mens.png b/app/assets/images/emoji/mens.png
new file mode 100755
index 00000000..abccfc9f
Binary files /dev/null and b/app/assets/images/emoji/mens.png differ
diff --git a/app/assets/images/emoji/metal.png b/app/assets/images/emoji/metal.png
new file mode 100755
index 00000000..94f1fda2
Binary files /dev/null and b/app/assets/images/emoji/metal.png differ
diff --git a/app/assets/images/emoji/metro.png b/app/assets/images/emoji/metro.png
new file mode 100755
index 00000000..4acf5ab3
Binary files /dev/null and b/app/assets/images/emoji/metro.png differ
diff --git a/app/assets/images/emoji/microphone.png b/app/assets/images/emoji/microphone.png
new file mode 100755
index 00000000..68c74ada
Binary files /dev/null and b/app/assets/images/emoji/microphone.png differ
diff --git a/app/assets/images/emoji/microscope.png b/app/assets/images/emoji/microscope.png
new file mode 100755
index 00000000..f11d54c0
Binary files /dev/null and b/app/assets/images/emoji/microscope.png differ
diff --git a/app/assets/images/emoji/milky_way.png b/app/assets/images/emoji/milky_way.png
new file mode 100755
index 00000000..901090a1
Binary files /dev/null and b/app/assets/images/emoji/milky_way.png differ
diff --git a/app/assets/images/emoji/minibus.png b/app/assets/images/emoji/minibus.png
new file mode 100755
index 00000000..c52cef23
Binary files /dev/null and b/app/assets/images/emoji/minibus.png differ
diff --git a/app/assets/images/emoji/minidisc.png b/app/assets/images/emoji/minidisc.png
new file mode 100755
index 00000000..e19cc5d0
Binary files /dev/null and b/app/assets/images/emoji/minidisc.png differ
diff --git a/app/assets/images/emoji/mobile_phone_off.png b/app/assets/images/emoji/mobile_phone_off.png
new file mode 100755
index 00000000..fa16c763
Binary files /dev/null and b/app/assets/images/emoji/mobile_phone_off.png differ
diff --git a/app/assets/images/emoji/money_with_wings.png b/app/assets/images/emoji/money_with_wings.png
new file mode 100755
index 00000000..135e3981
Binary files /dev/null and b/app/assets/images/emoji/money_with_wings.png differ
diff --git a/app/assets/images/emoji/moneybag.png b/app/assets/images/emoji/moneybag.png
new file mode 100755
index 00000000..5546c04b
Binary files /dev/null and b/app/assets/images/emoji/moneybag.png differ
diff --git a/app/assets/images/emoji/monkey.png b/app/assets/images/emoji/monkey.png
new file mode 100755
index 00000000..64070359
Binary files /dev/null and b/app/assets/images/emoji/monkey.png differ
diff --git a/app/assets/images/emoji/monkey_face.png b/app/assets/images/emoji/monkey_face.png
new file mode 100755
index 00000000..6964cf4d
Binary files /dev/null and b/app/assets/images/emoji/monkey_face.png differ
diff --git a/app/assets/images/emoji/monorail.png b/app/assets/images/emoji/monorail.png
new file mode 100755
index 00000000..913d3002
Binary files /dev/null and b/app/assets/images/emoji/monorail.png differ
diff --git a/app/assets/images/emoji/moon.png b/app/assets/images/emoji/moon.png
new file mode 100755
index 00000000..afdb450d
Binary files /dev/null and b/app/assets/images/emoji/moon.png differ
diff --git a/app/assets/images/emoji/mortar_board.png b/app/assets/images/emoji/mortar_board.png
new file mode 100755
index 00000000..2e811b09
Binary files /dev/null and b/app/assets/images/emoji/mortar_board.png differ
diff --git a/app/assets/images/emoji/mount_fuji.png b/app/assets/images/emoji/mount_fuji.png
new file mode 100755
index 00000000..4c313e58
Binary files /dev/null and b/app/assets/images/emoji/mount_fuji.png differ
diff --git a/app/assets/images/emoji/mountain_bicyclist.png b/app/assets/images/emoji/mountain_bicyclist.png
new file mode 100755
index 00000000..b6988975
Binary files /dev/null and b/app/assets/images/emoji/mountain_bicyclist.png differ
diff --git a/app/assets/images/emoji/mountain_cableway.png b/app/assets/images/emoji/mountain_cableway.png
new file mode 100755
index 00000000..5688bb23
Binary files /dev/null and b/app/assets/images/emoji/mountain_cableway.png differ
diff --git a/app/assets/images/emoji/mountain_railway.png b/app/assets/images/emoji/mountain_railway.png
new file mode 100755
index 00000000..1f3d1aab
Binary files /dev/null and b/app/assets/images/emoji/mountain_railway.png differ
diff --git a/app/assets/images/emoji/mouse.png b/app/assets/images/emoji/mouse.png
new file mode 100755
index 00000000..8ff162e2
Binary files /dev/null and b/app/assets/images/emoji/mouse.png differ
diff --git a/app/assets/images/emoji/mouse2.png b/app/assets/images/emoji/mouse2.png
new file mode 100755
index 00000000..2d777e5e
Binary files /dev/null and b/app/assets/images/emoji/mouse2.png differ
diff --git a/app/assets/images/emoji/movie_camera.png b/app/assets/images/emoji/movie_camera.png
new file mode 100755
index 00000000..9c143840
Binary files /dev/null and b/app/assets/images/emoji/movie_camera.png differ
diff --git a/app/assets/images/emoji/moyai.png b/app/assets/images/emoji/moyai.png
new file mode 100755
index 00000000..61a1a9c2
Binary files /dev/null and b/app/assets/images/emoji/moyai.png differ
diff --git a/app/assets/images/emoji/muscle.png b/app/assets/images/emoji/muscle.png
new file mode 100755
index 00000000..19f92efb
Binary files /dev/null and b/app/assets/images/emoji/muscle.png differ
diff --git a/app/assets/images/emoji/mushroom.png b/app/assets/images/emoji/mushroom.png
new file mode 100755
index 00000000..5eeed8e7
Binary files /dev/null and b/app/assets/images/emoji/mushroom.png differ
diff --git a/app/assets/images/emoji/musical_keyboard.png b/app/assets/images/emoji/musical_keyboard.png
new file mode 100755
index 00000000..93647a4a
Binary files /dev/null and b/app/assets/images/emoji/musical_keyboard.png differ
diff --git a/app/assets/images/emoji/musical_note.png b/app/assets/images/emoji/musical_note.png
new file mode 100755
index 00000000..68b261bc
Binary files /dev/null and b/app/assets/images/emoji/musical_note.png differ
diff --git a/app/assets/images/emoji/musical_score.png b/app/assets/images/emoji/musical_score.png
new file mode 100755
index 00000000..0c927d32
Binary files /dev/null and b/app/assets/images/emoji/musical_score.png differ
diff --git a/app/assets/images/emoji/mute.png b/app/assets/images/emoji/mute.png
new file mode 100755
index 00000000..4cf67c36
Binary files /dev/null and b/app/assets/images/emoji/mute.png differ
diff --git a/app/assets/images/emoji/nail_care.png b/app/assets/images/emoji/nail_care.png
new file mode 100755
index 00000000..6a66e63d
Binary files /dev/null and b/app/assets/images/emoji/nail_care.png differ
diff --git a/app/assets/images/emoji/name_badge.png b/app/assets/images/emoji/name_badge.png
new file mode 100755
index 00000000..2b712dcd
Binary files /dev/null and b/app/assets/images/emoji/name_badge.png differ
diff --git a/app/assets/images/emoji/neckbeard.png b/app/assets/images/emoji/neckbeard.png
new file mode 100755
index 00000000..15108fc9
Binary files /dev/null and b/app/assets/images/emoji/neckbeard.png differ
diff --git a/app/assets/images/emoji/necktie.png b/app/assets/images/emoji/necktie.png
new file mode 100755
index 00000000..80461c66
Binary files /dev/null and b/app/assets/images/emoji/necktie.png differ
diff --git a/app/assets/images/emoji/negative_squared_cross_mark.png b/app/assets/images/emoji/negative_squared_cross_mark.png
new file mode 100755
index 00000000..b47a0cec
Binary files /dev/null and b/app/assets/images/emoji/negative_squared_cross_mark.png differ
diff --git a/app/assets/images/emoji/neutral_face.png b/app/assets/images/emoji/neutral_face.png
new file mode 100755
index 00000000..682a1ba0
Binary files /dev/null and b/app/assets/images/emoji/neutral_face.png differ
diff --git a/app/assets/images/emoji/new.png b/app/assets/images/emoji/new.png
new file mode 100755
index 00000000..28d1570e
Binary files /dev/null and b/app/assets/images/emoji/new.png differ
diff --git a/app/assets/images/emoji/new_moon.png b/app/assets/images/emoji/new_moon.png
new file mode 100755
index 00000000..540239b1
Binary files /dev/null and b/app/assets/images/emoji/new_moon.png differ
diff --git a/app/assets/images/emoji/new_moon_with_face.png b/app/assets/images/emoji/new_moon_with_face.png
new file mode 100755
index 00000000..b9aff7a0
Binary files /dev/null and b/app/assets/images/emoji/new_moon_with_face.png differ
diff --git a/app/assets/images/emoji/newspaper.png b/app/assets/images/emoji/newspaper.png
new file mode 100755
index 00000000..d171394e
Binary files /dev/null and b/app/assets/images/emoji/newspaper.png differ
diff --git a/app/assets/images/emoji/ng.png b/app/assets/images/emoji/ng.png
new file mode 100755
index 00000000..2ca180ae
Binary files /dev/null and b/app/assets/images/emoji/ng.png differ
diff --git a/app/assets/images/emoji/nine.png b/app/assets/images/emoji/nine.png
new file mode 100755
index 00000000..8006cc90
Binary files /dev/null and b/app/assets/images/emoji/nine.png differ
diff --git a/app/assets/images/emoji/no_bell.png b/app/assets/images/emoji/no_bell.png
new file mode 100755
index 00000000..613b81cd
Binary files /dev/null and b/app/assets/images/emoji/no_bell.png differ
diff --git a/app/assets/images/emoji/no_bicycles.png b/app/assets/images/emoji/no_bicycles.png
new file mode 100755
index 00000000..4b262166
Binary files /dev/null and b/app/assets/images/emoji/no_bicycles.png differ
diff --git a/app/assets/images/emoji/no_entry.png b/app/assets/images/emoji/no_entry.png
new file mode 100755
index 00000000..cf2086a8
Binary files /dev/null and b/app/assets/images/emoji/no_entry.png differ
diff --git a/app/assets/images/emoji/no_entry_sign.png b/app/assets/images/emoji/no_entry_sign.png
new file mode 100755
index 00000000..a8444d18
Binary files /dev/null and b/app/assets/images/emoji/no_entry_sign.png differ
diff --git a/app/assets/images/emoji/no_good.png b/app/assets/images/emoji/no_good.png
new file mode 100755
index 00000000..d459a35b
Binary files /dev/null and b/app/assets/images/emoji/no_good.png differ
diff --git a/app/assets/images/emoji/no_mobile_phones.png b/app/assets/images/emoji/no_mobile_phones.png
new file mode 100755
index 00000000..41df57cf
Binary files /dev/null and b/app/assets/images/emoji/no_mobile_phones.png differ
diff --git a/app/assets/images/emoji/no_mouth.png b/app/assets/images/emoji/no_mouth.png
new file mode 100755
index 00000000..d9ec7ca7
Binary files /dev/null and b/app/assets/images/emoji/no_mouth.png differ
diff --git a/app/assets/images/emoji/no_pedestrians.png b/app/assets/images/emoji/no_pedestrians.png
new file mode 100755
index 00000000..c35f530b
Binary files /dev/null and b/app/assets/images/emoji/no_pedestrians.png differ
diff --git a/app/assets/images/emoji/no_smoking.png b/app/assets/images/emoji/no_smoking.png
new file mode 100755
index 00000000..5880ddfd
Binary files /dev/null and b/app/assets/images/emoji/no_smoking.png differ
diff --git a/app/assets/images/emoji/non-potable_water.png b/app/assets/images/emoji/non-potable_water.png
new file mode 100755
index 00000000..1b29d35b
Binary files /dev/null and b/app/assets/images/emoji/non-potable_water.png differ
diff --git a/app/assets/images/emoji/nose.png b/app/assets/images/emoji/nose.png
new file mode 100755
index 00000000..ad17c16c
Binary files /dev/null and b/app/assets/images/emoji/nose.png differ
diff --git a/app/assets/images/emoji/notebook.png b/app/assets/images/emoji/notebook.png
new file mode 100755
index 00000000..07ea6087
Binary files /dev/null and b/app/assets/images/emoji/notebook.png differ
diff --git a/app/assets/images/emoji/notebook_with_decorative_cover.png b/app/assets/images/emoji/notebook_with_decorative_cover.png
new file mode 100755
index 00000000..4f3b14c8
Binary files /dev/null and b/app/assets/images/emoji/notebook_with_decorative_cover.png differ
diff --git a/app/assets/images/emoji/notes.png b/app/assets/images/emoji/notes.png
new file mode 100755
index 00000000..0956d6ab
Binary files /dev/null and b/app/assets/images/emoji/notes.png differ
diff --git a/app/assets/images/emoji/nut_and_bolt.png b/app/assets/images/emoji/nut_and_bolt.png
new file mode 100755
index 00000000..bddfa72a
Binary files /dev/null and b/app/assets/images/emoji/nut_and_bolt.png differ
diff --git a/app/assets/images/emoji/o.png b/app/assets/images/emoji/o.png
new file mode 100755
index 00000000..0ededebe
Binary files /dev/null and b/app/assets/images/emoji/o.png differ
diff --git a/app/assets/images/emoji/o2.png b/app/assets/images/emoji/o2.png
new file mode 100755
index 00000000..d85f9fb9
Binary files /dev/null and b/app/assets/images/emoji/o2.png differ
diff --git a/app/assets/images/emoji/ocean.png b/app/assets/images/emoji/ocean.png
new file mode 100755
index 00000000..f8d520cd
Binary files /dev/null and b/app/assets/images/emoji/ocean.png differ
diff --git a/app/assets/images/emoji/octocat.png b/app/assets/images/emoji/octocat.png
new file mode 100755
index 00000000..3fc20503
Binary files /dev/null and b/app/assets/images/emoji/octocat.png differ
diff --git a/app/assets/images/emoji/octopus.png b/app/assets/images/emoji/octopus.png
new file mode 100755
index 00000000..52ce64b4
Binary files /dev/null and b/app/assets/images/emoji/octopus.png differ
diff --git a/app/assets/images/emoji/oden.png b/app/assets/images/emoji/oden.png
new file mode 100755
index 00000000..73add1c7
Binary files /dev/null and b/app/assets/images/emoji/oden.png differ
diff --git a/app/assets/images/emoji/office.png b/app/assets/images/emoji/office.png
new file mode 100755
index 00000000..ea9281a4
Binary files /dev/null and b/app/assets/images/emoji/office.png differ
diff --git a/app/assets/images/emoji/ok.png b/app/assets/images/emoji/ok.png
new file mode 100755
index 00000000..6433d1a9
Binary files /dev/null and b/app/assets/images/emoji/ok.png differ
diff --git a/app/assets/images/emoji/ok_hand.png b/app/assets/images/emoji/ok_hand.png
new file mode 100755
index 00000000..80c5aebb
Binary files /dev/null and b/app/assets/images/emoji/ok_hand.png differ
diff --git a/app/assets/images/emoji/ok_woman.png b/app/assets/images/emoji/ok_woman.png
new file mode 100755
index 00000000..e8b98194
Binary files /dev/null and b/app/assets/images/emoji/ok_woman.png differ
diff --git a/app/assets/images/emoji/older_man.png b/app/assets/images/emoji/older_man.png
new file mode 100755
index 00000000..149f0cfb
Binary files /dev/null and b/app/assets/images/emoji/older_man.png differ
diff --git a/app/assets/images/emoji/older_woman.png b/app/assets/images/emoji/older_woman.png
new file mode 100755
index 00000000..f839565f
Binary files /dev/null and b/app/assets/images/emoji/older_woman.png differ
diff --git a/app/assets/images/emoji/on.png b/app/assets/images/emoji/on.png
new file mode 100755
index 00000000..3595387f
Binary files /dev/null and b/app/assets/images/emoji/on.png differ
diff --git a/app/assets/images/emoji/oncoming_automobile.png b/app/assets/images/emoji/oncoming_automobile.png
new file mode 100755
index 00000000..cb46de22
Binary files /dev/null and b/app/assets/images/emoji/oncoming_automobile.png differ
diff --git a/app/assets/images/emoji/oncoming_bus.png b/app/assets/images/emoji/oncoming_bus.png
new file mode 100755
index 00000000..3695f762
Binary files /dev/null and b/app/assets/images/emoji/oncoming_bus.png differ
diff --git a/app/assets/images/emoji/oncoming_police_car.png b/app/assets/images/emoji/oncoming_police_car.png
new file mode 100755
index 00000000..af20e7ef
Binary files /dev/null and b/app/assets/images/emoji/oncoming_police_car.png differ
diff --git a/app/assets/images/emoji/oncoming_taxi.png b/app/assets/images/emoji/oncoming_taxi.png
new file mode 100755
index 00000000..f78cf310
Binary files /dev/null and b/app/assets/images/emoji/oncoming_taxi.png differ
diff --git a/app/assets/images/emoji/one.png b/app/assets/images/emoji/one.png
new file mode 100755
index 00000000..2d1f9f8c
Binary files /dev/null and b/app/assets/images/emoji/one.png differ
diff --git a/app/assets/images/emoji/open_file_folder.png b/app/assets/images/emoji/open_file_folder.png
new file mode 100755
index 00000000..2bbbbf5e
Binary files /dev/null and b/app/assets/images/emoji/open_file_folder.png differ
diff --git a/app/assets/images/emoji/open_hands.png b/app/assets/images/emoji/open_hands.png
new file mode 100755
index 00000000..2cc25bd4
Binary files /dev/null and b/app/assets/images/emoji/open_hands.png differ
diff --git a/app/assets/images/emoji/ophiuchus.png b/app/assets/images/emoji/ophiuchus.png
new file mode 100755
index 00000000..4eef715b
Binary files /dev/null and b/app/assets/images/emoji/ophiuchus.png differ
diff --git a/app/assets/images/emoji/orange_book.png b/app/assets/images/emoji/orange_book.png
new file mode 100755
index 00000000..49650d59
Binary files /dev/null and b/app/assets/images/emoji/orange_book.png differ
diff --git a/app/assets/images/emoji/outbox_tray.png b/app/assets/images/emoji/outbox_tray.png
new file mode 100755
index 00000000..7ad15e64
Binary files /dev/null and b/app/assets/images/emoji/outbox_tray.png differ
diff --git a/app/assets/images/emoji/ox.png b/app/assets/images/emoji/ox.png
new file mode 100755
index 00000000..f7669802
Binary files /dev/null and b/app/assets/images/emoji/ox.png differ
diff --git a/app/assets/images/emoji/page_facing_up.png b/app/assets/images/emoji/page_facing_up.png
new file mode 100755
index 00000000..64cd2e1b
Binary files /dev/null and b/app/assets/images/emoji/page_facing_up.png differ
diff --git a/app/assets/images/emoji/page_with_curl.png b/app/assets/images/emoji/page_with_curl.png
new file mode 100755
index 00000000..bf8f979d
Binary files /dev/null and b/app/assets/images/emoji/page_with_curl.png differ
diff --git a/app/assets/images/emoji/pager.png b/app/assets/images/emoji/pager.png
new file mode 100755
index 00000000..e3e1fc44
Binary files /dev/null and b/app/assets/images/emoji/pager.png differ
diff --git a/app/assets/images/emoji/palm_tree.png b/app/assets/images/emoji/palm_tree.png
new file mode 100755
index 00000000..d534785e
Binary files /dev/null and b/app/assets/images/emoji/palm_tree.png differ
diff --git a/app/assets/images/emoji/panda_face.png b/app/assets/images/emoji/panda_face.png
new file mode 100755
index 00000000..a794fb17
Binary files /dev/null and b/app/assets/images/emoji/panda_face.png differ
diff --git a/app/assets/images/emoji/paperclip.png b/app/assets/images/emoji/paperclip.png
new file mode 100755
index 00000000..774412dc
Binary files /dev/null and b/app/assets/images/emoji/paperclip.png differ
diff --git a/app/assets/images/emoji/parking.png b/app/assets/images/emoji/parking.png
new file mode 100755
index 00000000..c24af81c
Binary files /dev/null and b/app/assets/images/emoji/parking.png differ
diff --git a/app/assets/images/emoji/part_alternation_mark.png b/app/assets/images/emoji/part_alternation_mark.png
new file mode 100755
index 00000000..45dc9b85
Binary files /dev/null and b/app/assets/images/emoji/part_alternation_mark.png differ
diff --git a/app/assets/images/emoji/partly_sunny.png b/app/assets/images/emoji/partly_sunny.png
new file mode 100755
index 00000000..020dd5ff
Binary files /dev/null and b/app/assets/images/emoji/partly_sunny.png differ
diff --git a/app/assets/images/emoji/passport_control.png b/app/assets/images/emoji/passport_control.png
new file mode 100755
index 00000000..675b76d3
Binary files /dev/null and b/app/assets/images/emoji/passport_control.png differ
diff --git a/app/assets/images/emoji/paw_prints.png b/app/assets/images/emoji/paw_prints.png
new file mode 100755
index 00000000..89b9fec9
Binary files /dev/null and b/app/assets/images/emoji/paw_prints.png differ
diff --git a/app/assets/images/emoji/peach.png b/app/assets/images/emoji/peach.png
new file mode 100755
index 00000000..ee2139ec
Binary files /dev/null and b/app/assets/images/emoji/peach.png differ
diff --git a/app/assets/images/emoji/pear.png b/app/assets/images/emoji/pear.png
new file mode 100755
index 00000000..f24aca8c
Binary files /dev/null and b/app/assets/images/emoji/pear.png differ
diff --git a/app/assets/images/emoji/pencil.png b/app/assets/images/emoji/pencil.png
new file mode 100755
index 00000000..fc97ddbc
Binary files /dev/null and b/app/assets/images/emoji/pencil.png differ
diff --git a/app/assets/images/emoji/pencil2.png b/app/assets/images/emoji/pencil2.png
new file mode 100755
index 00000000..e624373b
Binary files /dev/null and b/app/assets/images/emoji/pencil2.png differ
diff --git a/app/assets/images/emoji/penguin.png b/app/assets/images/emoji/penguin.png
new file mode 100755
index 00000000..d8edbcb8
Binary files /dev/null and b/app/assets/images/emoji/penguin.png differ
diff --git a/app/assets/images/emoji/pensive.png b/app/assets/images/emoji/pensive.png
new file mode 100755
index 00000000..4159f3c4
Binary files /dev/null and b/app/assets/images/emoji/pensive.png differ
diff --git a/app/assets/images/emoji/performing_arts.png b/app/assets/images/emoji/performing_arts.png
new file mode 100755
index 00000000..899fbe5a
Binary files /dev/null and b/app/assets/images/emoji/performing_arts.png differ
diff --git a/app/assets/images/emoji/persevere.png b/app/assets/images/emoji/persevere.png
new file mode 100755
index 00000000..f99f6da4
Binary files /dev/null and b/app/assets/images/emoji/persevere.png differ
diff --git a/app/assets/images/emoji/person_frowning.png b/app/assets/images/emoji/person_frowning.png
new file mode 100755
index 00000000..6f34d5e1
Binary files /dev/null and b/app/assets/images/emoji/person_frowning.png differ
diff --git a/app/assets/images/emoji/person_with_blond_hair.png b/app/assets/images/emoji/person_with_blond_hair.png
new file mode 100755
index 00000000..c144301c
Binary files /dev/null and b/app/assets/images/emoji/person_with_blond_hair.png differ
diff --git a/app/assets/images/emoji/person_with_pouting_face.png b/app/assets/images/emoji/person_with_pouting_face.png
new file mode 100755
index 00000000..c4a95c3b
Binary files /dev/null and b/app/assets/images/emoji/person_with_pouting_face.png differ
diff --git a/app/assets/images/emoji/phone.png b/app/assets/images/emoji/phone.png
new file mode 100755
index 00000000..87d2559b
Binary files /dev/null and b/app/assets/images/emoji/phone.png differ
diff --git a/app/assets/images/emoji/pig.png b/app/assets/images/emoji/pig.png
new file mode 100755
index 00000000..f7f273c7
Binary files /dev/null and b/app/assets/images/emoji/pig.png differ
diff --git a/app/assets/images/emoji/pig2.png b/app/assets/images/emoji/pig2.png
new file mode 100755
index 00000000..fec3374d
Binary files /dev/null and b/app/assets/images/emoji/pig2.png differ
diff --git a/app/assets/images/emoji/pig_nose.png b/app/assets/images/emoji/pig_nose.png
new file mode 100755
index 00000000..38d61244
Binary files /dev/null and b/app/assets/images/emoji/pig_nose.png differ
diff --git a/app/assets/images/emoji/pill.png b/app/assets/images/emoji/pill.png
new file mode 100755
index 00000000..cd84a78f
Binary files /dev/null and b/app/assets/images/emoji/pill.png differ
diff --git a/app/assets/images/emoji/pineapple.png b/app/assets/images/emoji/pineapple.png
new file mode 100755
index 00000000..d6f8e287
Binary files /dev/null and b/app/assets/images/emoji/pineapple.png differ
diff --git a/app/assets/images/emoji/pisces.png b/app/assets/images/emoji/pisces.png
new file mode 100755
index 00000000..5a2da0a0
Binary files /dev/null and b/app/assets/images/emoji/pisces.png differ
diff --git a/app/assets/images/emoji/pizza.png b/app/assets/images/emoji/pizza.png
new file mode 100755
index 00000000..460367d0
Binary files /dev/null and b/app/assets/images/emoji/pizza.png differ
diff --git a/app/assets/images/emoji/plus1.png b/app/assets/images/emoji/plus1.png
new file mode 100755
index 00000000..81786c1d
Binary files /dev/null and b/app/assets/images/emoji/plus1.png differ
diff --git a/app/assets/images/emoji/point_down.png b/app/assets/images/emoji/point_down.png
new file mode 100755
index 00000000..658c6d91
Binary files /dev/null and b/app/assets/images/emoji/point_down.png differ
diff --git a/app/assets/images/emoji/point_left.png b/app/assets/images/emoji/point_left.png
new file mode 100755
index 00000000..38a99b43
Binary files /dev/null and b/app/assets/images/emoji/point_left.png differ
diff --git a/app/assets/images/emoji/point_right.png b/app/assets/images/emoji/point_right.png
new file mode 100755
index 00000000..6f9f029a
Binary files /dev/null and b/app/assets/images/emoji/point_right.png differ
diff --git a/app/assets/images/emoji/point_up.png b/app/assets/images/emoji/point_up.png
new file mode 100755
index 00000000..01896e21
Binary files /dev/null and b/app/assets/images/emoji/point_up.png differ
diff --git a/app/assets/images/emoji/point_up_2.png b/app/assets/images/emoji/point_up_2.png
new file mode 100755
index 00000000..1cfe7367
Binary files /dev/null and b/app/assets/images/emoji/point_up_2.png differ
diff --git a/app/assets/images/emoji/police_car.png b/app/assets/images/emoji/police_car.png
new file mode 100755
index 00000000..b8f17275
Binary files /dev/null and b/app/assets/images/emoji/police_car.png differ
diff --git a/app/assets/images/emoji/poodle.png b/app/assets/images/emoji/poodle.png
new file mode 100755
index 00000000..adac80bd
Binary files /dev/null and b/app/assets/images/emoji/poodle.png differ
diff --git a/app/assets/images/emoji/poop.png b/app/assets/images/emoji/poop.png
new file mode 100755
index 00000000..73a4dc84
Binary files /dev/null and b/app/assets/images/emoji/poop.png differ
diff --git a/app/assets/images/emoji/post_office.png b/app/assets/images/emoji/post_office.png
new file mode 100755
index 00000000..43b59e30
Binary files /dev/null and b/app/assets/images/emoji/post_office.png differ
diff --git a/app/assets/images/emoji/postal_horn.png b/app/assets/images/emoji/postal_horn.png
new file mode 100755
index 00000000..e9b713bb
Binary files /dev/null and b/app/assets/images/emoji/postal_horn.png differ
diff --git a/app/assets/images/emoji/postbox.png b/app/assets/images/emoji/postbox.png
new file mode 100755
index 00000000..ce04b700
Binary files /dev/null and b/app/assets/images/emoji/postbox.png differ
diff --git a/app/assets/images/emoji/potable_water.png b/app/assets/images/emoji/potable_water.png
new file mode 100755
index 00000000..e9fd5607
Binary files /dev/null and b/app/assets/images/emoji/potable_water.png differ
diff --git a/app/assets/images/emoji/pouch.png b/app/assets/images/emoji/pouch.png
new file mode 100755
index 00000000..0bc5879f
Binary files /dev/null and b/app/assets/images/emoji/pouch.png differ
diff --git a/app/assets/images/emoji/poultry_leg.png b/app/assets/images/emoji/poultry_leg.png
new file mode 100755
index 00000000..43ad8596
Binary files /dev/null and b/app/assets/images/emoji/poultry_leg.png differ
diff --git a/app/assets/images/emoji/pound.png b/app/assets/images/emoji/pound.png
new file mode 100755
index 00000000..f8be91d7
Binary files /dev/null and b/app/assets/images/emoji/pound.png differ
diff --git a/app/assets/images/emoji/pouting_cat.png b/app/assets/images/emoji/pouting_cat.png
new file mode 100755
index 00000000..4325fd48
Binary files /dev/null and b/app/assets/images/emoji/pouting_cat.png differ
diff --git a/app/assets/images/emoji/pray.png b/app/assets/images/emoji/pray.png
new file mode 100755
index 00000000..f86c992d
Binary files /dev/null and b/app/assets/images/emoji/pray.png differ
diff --git a/app/assets/images/emoji/princess.png b/app/assets/images/emoji/princess.png
new file mode 100755
index 00000000..1ebb2ce9
Binary files /dev/null and b/app/assets/images/emoji/princess.png differ
diff --git a/app/assets/images/emoji/punch.png b/app/assets/images/emoji/punch.png
new file mode 100755
index 00000000..277047b7
Binary files /dev/null and b/app/assets/images/emoji/punch.png differ
diff --git a/app/assets/images/emoji/purple_heart.png b/app/assets/images/emoji/purple_heart.png
new file mode 100755
index 00000000..d5f87504
Binary files /dev/null and b/app/assets/images/emoji/purple_heart.png differ
diff --git a/app/assets/images/emoji/purse.png b/app/assets/images/emoji/purse.png
new file mode 100755
index 00000000..8f06a2b9
Binary files /dev/null and b/app/assets/images/emoji/purse.png differ
diff --git a/app/assets/images/emoji/pushpin.png b/app/assets/images/emoji/pushpin.png
new file mode 100755
index 00000000..540c4ecb
Binary files /dev/null and b/app/assets/images/emoji/pushpin.png differ
diff --git a/app/assets/images/emoji/put_litter_in_its_place.png b/app/assets/images/emoji/put_litter_in_its_place.png
new file mode 100755
index 00000000..c2e350c2
Binary files /dev/null and b/app/assets/images/emoji/put_litter_in_its_place.png differ
diff --git a/app/assets/images/emoji/question.png b/app/assets/images/emoji/question.png
new file mode 100755
index 00000000..38cedf56
Binary files /dev/null and b/app/assets/images/emoji/question.png differ
diff --git a/app/assets/images/emoji/rabbit.png b/app/assets/images/emoji/rabbit.png
new file mode 100755
index 00000000..5cb3ef6f
Binary files /dev/null and b/app/assets/images/emoji/rabbit.png differ
diff --git a/app/assets/images/emoji/rabbit2.png b/app/assets/images/emoji/rabbit2.png
new file mode 100755
index 00000000..5bc993e7
Binary files /dev/null and b/app/assets/images/emoji/rabbit2.png differ
diff --git a/app/assets/images/emoji/racehorse.png b/app/assets/images/emoji/racehorse.png
new file mode 100755
index 00000000..4d09c64d
Binary files /dev/null and b/app/assets/images/emoji/racehorse.png differ
diff --git a/app/assets/images/emoji/radio.png b/app/assets/images/emoji/radio.png
new file mode 100755
index 00000000..ea589efe
Binary files /dev/null and b/app/assets/images/emoji/radio.png differ
diff --git a/app/assets/images/emoji/radio_button.png b/app/assets/images/emoji/radio_button.png
new file mode 100755
index 00000000..63755eec
Binary files /dev/null and b/app/assets/images/emoji/radio_button.png differ
diff --git a/app/assets/images/emoji/rage.png b/app/assets/images/emoji/rage.png
new file mode 100755
index 00000000..c65ddff5
Binary files /dev/null and b/app/assets/images/emoji/rage.png differ
diff --git a/app/assets/images/emoji/rage1.png b/app/assets/images/emoji/rage1.png
new file mode 100755
index 00000000..1506ba40
Binary files /dev/null and b/app/assets/images/emoji/rage1.png differ
diff --git a/app/assets/images/emoji/rage2.png b/app/assets/images/emoji/rage2.png
new file mode 100755
index 00000000..f792e063
Binary files /dev/null and b/app/assets/images/emoji/rage2.png differ
diff --git a/app/assets/images/emoji/rage3.png b/app/assets/images/emoji/rage3.png
new file mode 100755
index 00000000..58764cbc
Binary files /dev/null and b/app/assets/images/emoji/rage3.png differ
diff --git a/app/assets/images/emoji/rage4.png b/app/assets/images/emoji/rage4.png
new file mode 100755
index 00000000..c726c94a
Binary files /dev/null and b/app/assets/images/emoji/rage4.png differ
diff --git a/app/assets/images/emoji/railway_car.png b/app/assets/images/emoji/railway_car.png
new file mode 100755
index 00000000..22361158
Binary files /dev/null and b/app/assets/images/emoji/railway_car.png differ
diff --git a/app/assets/images/emoji/rainbow.png b/app/assets/images/emoji/rainbow.png
new file mode 100755
index 00000000..6b1faa03
Binary files /dev/null and b/app/assets/images/emoji/rainbow.png differ
diff --git a/app/assets/images/emoji/raised_hand.png b/app/assets/images/emoji/raised_hand.png
new file mode 100755
index 00000000..e1741a40
Binary files /dev/null and b/app/assets/images/emoji/raised_hand.png differ
diff --git a/app/assets/images/emoji/raised_hands.png b/app/assets/images/emoji/raised_hands.png
new file mode 100755
index 00000000..e03142bd
Binary files /dev/null and b/app/assets/images/emoji/raised_hands.png differ
diff --git a/app/assets/images/emoji/ram.png b/app/assets/images/emoji/ram.png
new file mode 100755
index 00000000..5ea7bfbc
Binary files /dev/null and b/app/assets/images/emoji/ram.png differ
diff --git a/app/assets/images/emoji/ramen.png b/app/assets/images/emoji/ramen.png
new file mode 100755
index 00000000..78dc7d53
Binary files /dev/null and b/app/assets/images/emoji/ramen.png differ
diff --git a/app/assets/images/emoji/rat.png b/app/assets/images/emoji/rat.png
new file mode 100755
index 00000000..1c463dfd
Binary files /dev/null and b/app/assets/images/emoji/rat.png differ
diff --git a/app/assets/images/emoji/recycle.png b/app/assets/images/emoji/recycle.png
new file mode 100755
index 00000000..99104c0e
Binary files /dev/null and b/app/assets/images/emoji/recycle.png differ
diff --git a/app/assets/images/emoji/red_car.png b/app/assets/images/emoji/red_car.png
new file mode 100755
index 00000000..d70a2f06
Binary files /dev/null and b/app/assets/images/emoji/red_car.png differ
diff --git a/app/assets/images/emoji/red_circle.png b/app/assets/images/emoji/red_circle.png
new file mode 100755
index 00000000..b391289b
Binary files /dev/null and b/app/assets/images/emoji/red_circle.png differ
diff --git a/app/assets/images/emoji/registered.png b/app/assets/images/emoji/registered.png
new file mode 100755
index 00000000..31c68a80
Binary files /dev/null and b/app/assets/images/emoji/registered.png differ
diff --git a/app/assets/images/emoji/relaxed.png b/app/assets/images/emoji/relaxed.png
new file mode 100755
index 00000000..bbab82d3
Binary files /dev/null and b/app/assets/images/emoji/relaxed.png differ
diff --git a/app/assets/images/emoji/relieved.png b/app/assets/images/emoji/relieved.png
new file mode 100755
index 00000000..fa5f9e7f
Binary files /dev/null and b/app/assets/images/emoji/relieved.png differ
diff --git a/app/assets/images/emoji/repeat.png b/app/assets/images/emoji/repeat.png
new file mode 100755
index 00000000..80113b69
Binary files /dev/null and b/app/assets/images/emoji/repeat.png differ
diff --git a/app/assets/images/emoji/repeat_one.png b/app/assets/images/emoji/repeat_one.png
new file mode 100755
index 00000000..3c47bcc1
Binary files /dev/null and b/app/assets/images/emoji/repeat_one.png differ
diff --git a/app/assets/images/emoji/restroom.png b/app/assets/images/emoji/restroom.png
new file mode 100755
index 00000000..d6c111b2
Binary files /dev/null and b/app/assets/images/emoji/restroom.png differ
diff --git a/app/assets/images/emoji/revolving_hearts.png b/app/assets/images/emoji/revolving_hearts.png
new file mode 100755
index 00000000..ea3317c4
Binary files /dev/null and b/app/assets/images/emoji/revolving_hearts.png differ
diff --git a/app/assets/images/emoji/rewind.png b/app/assets/images/emoji/rewind.png
new file mode 100755
index 00000000..26289dc3
Binary files /dev/null and b/app/assets/images/emoji/rewind.png differ
diff --git a/app/assets/images/emoji/ribbon.png b/app/assets/images/emoji/ribbon.png
new file mode 100755
index 00000000..63ee5ba5
Binary files /dev/null and b/app/assets/images/emoji/ribbon.png differ
diff --git a/app/assets/images/emoji/rice.png b/app/assets/images/emoji/rice.png
new file mode 100755
index 00000000..1fd22027
Binary files /dev/null and b/app/assets/images/emoji/rice.png differ
diff --git a/app/assets/images/emoji/rice_ball.png b/app/assets/images/emoji/rice_ball.png
new file mode 100755
index 00000000..04f8a880
Binary files /dev/null and b/app/assets/images/emoji/rice_ball.png differ
diff --git a/app/assets/images/emoji/rice_cracker.png b/app/assets/images/emoji/rice_cracker.png
new file mode 100755
index 00000000..954c901e
Binary files /dev/null and b/app/assets/images/emoji/rice_cracker.png differ
diff --git a/app/assets/images/emoji/rice_scene.png b/app/assets/images/emoji/rice_scene.png
new file mode 100755
index 00000000..14361988
Binary files /dev/null and b/app/assets/images/emoji/rice_scene.png differ
diff --git a/app/assets/images/emoji/ring.png b/app/assets/images/emoji/ring.png
new file mode 100755
index 00000000..8a57fd68
Binary files /dev/null and b/app/assets/images/emoji/ring.png differ
diff --git a/app/assets/images/emoji/rocket.png b/app/assets/images/emoji/rocket.png
new file mode 100755
index 00000000..783078d3
Binary files /dev/null and b/app/assets/images/emoji/rocket.png differ
diff --git a/app/assets/images/emoji/roller_coaster.png b/app/assets/images/emoji/roller_coaster.png
new file mode 100755
index 00000000..9180b986
Binary files /dev/null and b/app/assets/images/emoji/roller_coaster.png differ
diff --git a/app/assets/images/emoji/rooster.png b/app/assets/images/emoji/rooster.png
new file mode 100755
index 00000000..fab23ad3
Binary files /dev/null and b/app/assets/images/emoji/rooster.png differ
diff --git a/app/assets/images/emoji/rose.png b/app/assets/images/emoji/rose.png
new file mode 100755
index 00000000..3479fbcb
Binary files /dev/null and b/app/assets/images/emoji/rose.png differ
diff --git a/app/assets/images/emoji/rotating_light.png b/app/assets/images/emoji/rotating_light.png
new file mode 100755
index 00000000..6cf4a775
Binary files /dev/null and b/app/assets/images/emoji/rotating_light.png differ
diff --git a/app/assets/images/emoji/round_pushpin.png b/app/assets/images/emoji/round_pushpin.png
new file mode 100755
index 00000000..e498e92c
Binary files /dev/null and b/app/assets/images/emoji/round_pushpin.png differ
diff --git a/app/assets/images/emoji/rowboat.png b/app/assets/images/emoji/rowboat.png
new file mode 100755
index 00000000..fe8ae3ec
Binary files /dev/null and b/app/assets/images/emoji/rowboat.png differ
diff --git a/app/assets/images/emoji/ru.png b/app/assets/images/emoji/ru.png
new file mode 100755
index 00000000..55fcf354
Binary files /dev/null and b/app/assets/images/emoji/ru.png differ
diff --git a/app/assets/images/emoji/rugby_football.png b/app/assets/images/emoji/rugby_football.png
new file mode 100755
index 00000000..f8db67d7
Binary files /dev/null and b/app/assets/images/emoji/rugby_football.png differ
diff --git a/app/assets/images/emoji/runner.png b/app/assets/images/emoji/runner.png
new file mode 100755
index 00000000..cb004296
Binary files /dev/null and b/app/assets/images/emoji/runner.png differ
diff --git a/app/assets/images/emoji/running.png b/app/assets/images/emoji/running.png
new file mode 100755
index 00000000..1ecfd905
Binary files /dev/null and b/app/assets/images/emoji/running.png differ
diff --git a/app/assets/images/emoji/running_shirt_with_sash.png b/app/assets/images/emoji/running_shirt_with_sash.png
new file mode 100755
index 00000000..0d68bba0
Binary files /dev/null and b/app/assets/images/emoji/running_shirt_with_sash.png differ
diff --git a/app/assets/images/emoji/sa.png b/app/assets/images/emoji/sa.png
new file mode 100755
index 00000000..387f098b
Binary files /dev/null and b/app/assets/images/emoji/sa.png differ
diff --git a/app/assets/images/emoji/sagittarius.png b/app/assets/images/emoji/sagittarius.png
new file mode 100755
index 00000000..8b5435ba
Binary files /dev/null and b/app/assets/images/emoji/sagittarius.png differ
diff --git a/app/assets/images/emoji/sailboat.png b/app/assets/images/emoji/sailboat.png
new file mode 100755
index 00000000..ff656dc6
Binary files /dev/null and b/app/assets/images/emoji/sailboat.png differ
diff --git a/app/assets/images/emoji/sake.png b/app/assets/images/emoji/sake.png
new file mode 100755
index 00000000..1f69907e
Binary files /dev/null and b/app/assets/images/emoji/sake.png differ
diff --git a/app/assets/images/emoji/sandal.png b/app/assets/images/emoji/sandal.png
new file mode 100755
index 00000000..0bb3f663
Binary files /dev/null and b/app/assets/images/emoji/sandal.png differ
diff --git a/app/assets/images/emoji/santa.png b/app/assets/images/emoji/santa.png
new file mode 100755
index 00000000..a2240c07
Binary files /dev/null and b/app/assets/images/emoji/santa.png differ
diff --git a/app/assets/images/emoji/satellite.png b/app/assets/images/emoji/satellite.png
new file mode 100755
index 00000000..3481cc2e
Binary files /dev/null and b/app/assets/images/emoji/satellite.png differ
diff --git a/app/assets/images/emoji/satisfied.png b/app/assets/images/emoji/satisfied.png
new file mode 100755
index 00000000..fe5629f4
Binary files /dev/null and b/app/assets/images/emoji/satisfied.png differ
diff --git a/app/assets/images/emoji/saxophone.png b/app/assets/images/emoji/saxophone.png
new file mode 100755
index 00000000..011559a7
Binary files /dev/null and b/app/assets/images/emoji/saxophone.png differ
diff --git a/app/assets/images/emoji/school.png b/app/assets/images/emoji/school.png
new file mode 100755
index 00000000..afd922bf
Binary files /dev/null and b/app/assets/images/emoji/school.png differ
diff --git a/app/assets/images/emoji/school_satchel.png b/app/assets/images/emoji/school_satchel.png
new file mode 100755
index 00000000..edfb19ae
Binary files /dev/null and b/app/assets/images/emoji/school_satchel.png differ
diff --git a/app/assets/images/emoji/scissors.png b/app/assets/images/emoji/scissors.png
new file mode 100755
index 00000000..be916043
Binary files /dev/null and b/app/assets/images/emoji/scissors.png differ
diff --git a/app/assets/images/emoji/scorpius.png b/app/assets/images/emoji/scorpius.png
new file mode 100755
index 00000000..67fcea16
Binary files /dev/null and b/app/assets/images/emoji/scorpius.png differ
diff --git a/app/assets/images/emoji/scream.png b/app/assets/images/emoji/scream.png
new file mode 100755
index 00000000..9e93c885
Binary files /dev/null and b/app/assets/images/emoji/scream.png differ
diff --git a/app/assets/images/emoji/scream_cat.png b/app/assets/images/emoji/scream_cat.png
new file mode 100755
index 00000000..d94cd34f
Binary files /dev/null and b/app/assets/images/emoji/scream_cat.png differ
diff --git a/app/assets/images/emoji/scroll.png b/app/assets/images/emoji/scroll.png
new file mode 100755
index 00000000..c5a10e6b
Binary files /dev/null and b/app/assets/images/emoji/scroll.png differ
diff --git a/app/assets/images/emoji/seat.png b/app/assets/images/emoji/seat.png
new file mode 100755
index 00000000..d1cb864b
Binary files /dev/null and b/app/assets/images/emoji/seat.png differ
diff --git a/app/assets/images/emoji/secret.png b/app/assets/images/emoji/secret.png
new file mode 100755
index 00000000..82e383a6
Binary files /dev/null and b/app/assets/images/emoji/secret.png differ
diff --git a/app/assets/images/emoji/see_no_evil.png b/app/assets/images/emoji/see_no_evil.png
new file mode 100755
index 00000000..0890a622
Binary files /dev/null and b/app/assets/images/emoji/see_no_evil.png differ
diff --git a/app/assets/images/emoji/seedling.png b/app/assets/images/emoji/seedling.png
new file mode 100755
index 00000000..f0eb5a6b
Binary files /dev/null and b/app/assets/images/emoji/seedling.png differ
diff --git a/app/assets/images/emoji/seven.png b/app/assets/images/emoji/seven.png
new file mode 100755
index 00000000..354e89ae
Binary files /dev/null and b/app/assets/images/emoji/seven.png differ
diff --git a/app/assets/images/emoji/shaved_ice.png b/app/assets/images/emoji/shaved_ice.png
new file mode 100755
index 00000000..0d0b382c
Binary files /dev/null and b/app/assets/images/emoji/shaved_ice.png differ
diff --git a/app/assets/images/emoji/sheep.png b/app/assets/images/emoji/sheep.png
new file mode 100755
index 00000000..c7277d28
Binary files /dev/null and b/app/assets/images/emoji/sheep.png differ
diff --git a/app/assets/images/emoji/shell.png b/app/assets/images/emoji/shell.png
new file mode 100755
index 00000000..3145b564
Binary files /dev/null and b/app/assets/images/emoji/shell.png differ
diff --git a/app/assets/images/emoji/ship.png b/app/assets/images/emoji/ship.png
new file mode 100755
index 00000000..5d2d8b60
Binary files /dev/null and b/app/assets/images/emoji/ship.png differ
diff --git a/app/assets/images/emoji/shipit.png b/app/assets/images/emoji/shipit.png
new file mode 100755
index 00000000..a58a47f6
Binary files /dev/null and b/app/assets/images/emoji/shipit.png differ
diff --git a/app/assets/images/emoji/shirt.png b/app/assets/images/emoji/shirt.png
new file mode 100755
index 00000000..297a6d63
Binary files /dev/null and b/app/assets/images/emoji/shirt.png differ
diff --git a/app/assets/images/emoji/shit.png b/app/assets/images/emoji/shit.png
new file mode 100755
index 00000000..73a4dc84
Binary files /dev/null and b/app/assets/images/emoji/shit.png differ
diff --git a/app/assets/images/emoji/shoe.png b/app/assets/images/emoji/shoe.png
new file mode 100755
index 00000000..45b82e61
Binary files /dev/null and b/app/assets/images/emoji/shoe.png differ
diff --git a/app/assets/images/emoji/shower.png b/app/assets/images/emoji/shower.png
new file mode 100755
index 00000000..94f82aac
Binary files /dev/null and b/app/assets/images/emoji/shower.png differ
diff --git a/app/assets/images/emoji/signal_strength.png b/app/assets/images/emoji/signal_strength.png
new file mode 100755
index 00000000..a4bd23eb
Binary files /dev/null and b/app/assets/images/emoji/signal_strength.png differ
diff --git a/app/assets/images/emoji/six.png b/app/assets/images/emoji/six.png
new file mode 100755
index 00000000..56880556
Binary files /dev/null and b/app/assets/images/emoji/six.png differ
diff --git a/app/assets/images/emoji/six_pointed_star.png b/app/assets/images/emoji/six_pointed_star.png
new file mode 100755
index 00000000..010f8f5f
Binary files /dev/null and b/app/assets/images/emoji/six_pointed_star.png differ
diff --git a/app/assets/images/emoji/ski.png b/app/assets/images/emoji/ski.png
new file mode 100755
index 00000000..98f5cb0f
Binary files /dev/null and b/app/assets/images/emoji/ski.png differ
diff --git a/app/assets/images/emoji/skull.png b/app/assets/images/emoji/skull.png
new file mode 100755
index 00000000..bd4ee382
Binary files /dev/null and b/app/assets/images/emoji/skull.png differ
diff --git a/app/assets/images/emoji/sleepy.png b/app/assets/images/emoji/sleepy.png
new file mode 100755
index 00000000..df4f55ef
Binary files /dev/null and b/app/assets/images/emoji/sleepy.png differ
diff --git a/app/assets/images/emoji/slot_machine.png b/app/assets/images/emoji/slot_machine.png
new file mode 100755
index 00000000..26f11483
Binary files /dev/null and b/app/assets/images/emoji/slot_machine.png differ
diff --git a/app/assets/images/emoji/small_blue_diamond.png b/app/assets/images/emoji/small_blue_diamond.png
new file mode 100755
index 00000000..5a7b5d55
Binary files /dev/null and b/app/assets/images/emoji/small_blue_diamond.png differ
diff --git a/app/assets/images/emoji/small_orange_diamond.png b/app/assets/images/emoji/small_orange_diamond.png
new file mode 100755
index 00000000..04941d37
Binary files /dev/null and b/app/assets/images/emoji/small_orange_diamond.png differ
diff --git a/app/assets/images/emoji/small_red_triangle.png b/app/assets/images/emoji/small_red_triangle.png
new file mode 100755
index 00000000..8c4428da
Binary files /dev/null and b/app/assets/images/emoji/small_red_triangle.png differ
diff --git a/app/assets/images/emoji/small_red_triangle_down.png b/app/assets/images/emoji/small_red_triangle_down.png
new file mode 100755
index 00000000..94832f06
Binary files /dev/null and b/app/assets/images/emoji/small_red_triangle_down.png differ
diff --git a/app/assets/images/emoji/smile.png b/app/assets/images/emoji/smile.png
new file mode 100755
index 00000000..81a83968
Binary files /dev/null and b/app/assets/images/emoji/smile.png differ
diff --git a/app/assets/images/emoji/smile_cat.png b/app/assets/images/emoji/smile_cat.png
new file mode 100755
index 00000000..ad333ba3
Binary files /dev/null and b/app/assets/images/emoji/smile_cat.png differ
diff --git a/app/assets/images/emoji/smiley.png b/app/assets/images/emoji/smiley.png
new file mode 100755
index 00000000..77b581d6
Binary files /dev/null and b/app/assets/images/emoji/smiley.png differ
diff --git a/app/assets/images/emoji/smiley_cat.png b/app/assets/images/emoji/smiley_cat.png
new file mode 100755
index 00000000..dbf1b027
Binary files /dev/null and b/app/assets/images/emoji/smiley_cat.png differ
diff --git a/app/assets/images/emoji/smiling_imp.png b/app/assets/images/emoji/smiling_imp.png
new file mode 100755
index 00000000..d9040493
Binary files /dev/null and b/app/assets/images/emoji/smiling_imp.png differ
diff --git a/app/assets/images/emoji/smirk.png b/app/assets/images/emoji/smirk.png
new file mode 100755
index 00000000..bc6e5082
Binary files /dev/null and b/app/assets/images/emoji/smirk.png differ
diff --git a/app/assets/images/emoji/smirk_cat.png b/app/assets/images/emoji/smirk_cat.png
new file mode 100755
index 00000000..351565e2
Binary files /dev/null and b/app/assets/images/emoji/smirk_cat.png differ
diff --git a/app/assets/images/emoji/smoking.png b/app/assets/images/emoji/smoking.png
new file mode 100755
index 00000000..4aad6cbd
Binary files /dev/null and b/app/assets/images/emoji/smoking.png differ
diff --git a/app/assets/images/emoji/snail.png b/app/assets/images/emoji/snail.png
new file mode 100755
index 00000000..e75e69a8
Binary files /dev/null and b/app/assets/images/emoji/snail.png differ
diff --git a/app/assets/images/emoji/snake.png b/app/assets/images/emoji/snake.png
new file mode 100755
index 00000000..ef58933e
Binary files /dev/null and b/app/assets/images/emoji/snake.png differ
diff --git a/app/assets/images/emoji/snowboarder.png b/app/assets/images/emoji/snowboarder.png
new file mode 100755
index 00000000..aeda5c8d
Binary files /dev/null and b/app/assets/images/emoji/snowboarder.png differ
diff --git a/app/assets/images/emoji/snowflake.png b/app/assets/images/emoji/snowflake.png
new file mode 100755
index 00000000..54b68ff4
Binary files /dev/null and b/app/assets/images/emoji/snowflake.png differ
diff --git a/app/assets/images/emoji/snowman.png b/app/assets/images/emoji/snowman.png
new file mode 100755
index 00000000..a97902e5
Binary files /dev/null and b/app/assets/images/emoji/snowman.png differ
diff --git a/app/assets/images/emoji/sob.png b/app/assets/images/emoji/sob.png
new file mode 100755
index 00000000..1561df92
Binary files /dev/null and b/app/assets/images/emoji/sob.png differ
diff --git a/app/assets/images/emoji/soccer.png b/app/assets/images/emoji/soccer.png
new file mode 100755
index 00000000..1e118b5b
Binary files /dev/null and b/app/assets/images/emoji/soccer.png differ
diff --git a/app/assets/images/emoji/soon.png b/app/assets/images/emoji/soon.png
new file mode 100755
index 00000000..9386615a
Binary files /dev/null and b/app/assets/images/emoji/soon.png differ
diff --git a/app/assets/images/emoji/sos.png b/app/assets/images/emoji/sos.png
new file mode 100755
index 00000000..e3e16ef7
Binary files /dev/null and b/app/assets/images/emoji/sos.png differ
diff --git a/app/assets/images/emoji/sound.png b/app/assets/images/emoji/sound.png
new file mode 100755
index 00000000..6aa4dbff
Binary files /dev/null and b/app/assets/images/emoji/sound.png differ
diff --git a/app/assets/images/emoji/space_invader.png b/app/assets/images/emoji/space_invader.png
new file mode 100755
index 00000000..38404916
Binary files /dev/null and b/app/assets/images/emoji/space_invader.png differ
diff --git a/app/assets/images/emoji/spades.png b/app/assets/images/emoji/spades.png
new file mode 100755
index 00000000..133a1aba
Binary files /dev/null and b/app/assets/images/emoji/spades.png differ
diff --git a/app/assets/images/emoji/spaghetti.png b/app/assets/images/emoji/spaghetti.png
new file mode 100755
index 00000000..08de243f
Binary files /dev/null and b/app/assets/images/emoji/spaghetti.png differ
diff --git a/app/assets/images/emoji/sparkler.png b/app/assets/images/emoji/sparkler.png
new file mode 100755
index 00000000..4aabd7e0
Binary files /dev/null and b/app/assets/images/emoji/sparkler.png differ
diff --git a/app/assets/images/emoji/sparkles.png b/app/assets/images/emoji/sparkles.png
new file mode 100755
index 00000000..92138828
Binary files /dev/null and b/app/assets/images/emoji/sparkles.png differ
diff --git a/app/assets/images/emoji/speak_no_evil.png b/app/assets/images/emoji/speak_no_evil.png
new file mode 100755
index 00000000..87944c4d
Binary files /dev/null and b/app/assets/images/emoji/speak_no_evil.png differ
diff --git a/app/assets/images/emoji/speaker.png b/app/assets/images/emoji/speaker.png
new file mode 100755
index 00000000..470476e1
Binary files /dev/null and b/app/assets/images/emoji/speaker.png differ
diff --git a/app/assets/images/emoji/speech_balloon.png b/app/assets/images/emoji/speech_balloon.png
new file mode 100755
index 00000000..2896c278
Binary files /dev/null and b/app/assets/images/emoji/speech_balloon.png differ
diff --git a/app/assets/images/emoji/speedboat.png b/app/assets/images/emoji/speedboat.png
new file mode 100755
index 00000000..da6689b3
Binary files /dev/null and b/app/assets/images/emoji/speedboat.png differ
diff --git a/app/assets/images/emoji/squirrel.png b/app/assets/images/emoji/squirrel.png
new file mode 100755
index 00000000..a58a47f6
Binary files /dev/null and b/app/assets/images/emoji/squirrel.png differ
diff --git a/app/assets/images/emoji/star.png b/app/assets/images/emoji/star.png
new file mode 100755
index 00000000..1bfddc86
Binary files /dev/null and b/app/assets/images/emoji/star.png differ
diff --git a/app/assets/images/emoji/star2.png b/app/assets/images/emoji/star2.png
new file mode 100755
index 00000000..8b40ff4c
Binary files /dev/null and b/app/assets/images/emoji/star2.png differ
diff --git a/app/assets/images/emoji/stars.png b/app/assets/images/emoji/stars.png
new file mode 100755
index 00000000..097a8424
Binary files /dev/null and b/app/assets/images/emoji/stars.png differ
diff --git a/app/assets/images/emoji/station.png b/app/assets/images/emoji/station.png
new file mode 100755
index 00000000..e77daa8a
Binary files /dev/null and b/app/assets/images/emoji/station.png differ
diff --git a/app/assets/images/emoji/statue_of_liberty.png b/app/assets/images/emoji/statue_of_liberty.png
new file mode 100755
index 00000000..9ad90280
Binary files /dev/null and b/app/assets/images/emoji/statue_of_liberty.png differ
diff --git a/app/assets/images/emoji/steam_locomotive.png b/app/assets/images/emoji/steam_locomotive.png
new file mode 100755
index 00000000..54950776
Binary files /dev/null and b/app/assets/images/emoji/steam_locomotive.png differ
diff --git a/app/assets/images/emoji/stew.png b/app/assets/images/emoji/stew.png
new file mode 100755
index 00000000..e9687f9e
Binary files /dev/null and b/app/assets/images/emoji/stew.png differ
diff --git a/app/assets/images/emoji/straight_ruler.png b/app/assets/images/emoji/straight_ruler.png
new file mode 100755
index 00000000..af8cb4bc
Binary files /dev/null and b/app/assets/images/emoji/straight_ruler.png differ
diff --git a/app/assets/images/emoji/strawberry.png b/app/assets/images/emoji/strawberry.png
new file mode 100755
index 00000000..13eb827a
Binary files /dev/null and b/app/assets/images/emoji/strawberry.png differ
diff --git a/app/assets/images/emoji/sun_with_face.png b/app/assets/images/emoji/sun_with_face.png
new file mode 100755
index 00000000..ee276636
Binary files /dev/null and b/app/assets/images/emoji/sun_with_face.png differ
diff --git a/app/assets/images/emoji/sunflower.png b/app/assets/images/emoji/sunflower.png
new file mode 100755
index 00000000..d9bad194
Binary files /dev/null and b/app/assets/images/emoji/sunflower.png differ
diff --git a/app/assets/images/emoji/sunglasses.png b/app/assets/images/emoji/sunglasses.png
new file mode 100755
index 00000000..1c468a1c
Binary files /dev/null and b/app/assets/images/emoji/sunglasses.png differ
diff --git a/app/assets/images/emoji/sunny.png b/app/assets/images/emoji/sunny.png
new file mode 100755
index 00000000..d23c095e
Binary files /dev/null and b/app/assets/images/emoji/sunny.png differ
diff --git a/app/assets/images/emoji/sunrise.png b/app/assets/images/emoji/sunrise.png
new file mode 100755
index 00000000..ec58dcc9
Binary files /dev/null and b/app/assets/images/emoji/sunrise.png differ
diff --git a/app/assets/images/emoji/sunrise_over_mountains.png b/app/assets/images/emoji/sunrise_over_mountains.png
new file mode 100755
index 00000000..ebc3db14
Binary files /dev/null and b/app/assets/images/emoji/sunrise_over_mountains.png differ
diff --git a/app/assets/images/emoji/surfer.png b/app/assets/images/emoji/surfer.png
new file mode 100755
index 00000000..b067e8cb
Binary files /dev/null and b/app/assets/images/emoji/surfer.png differ
diff --git a/app/assets/images/emoji/sushi.png b/app/assets/images/emoji/sushi.png
new file mode 100755
index 00000000..0d179bd9
Binary files /dev/null and b/app/assets/images/emoji/sushi.png differ
diff --git a/app/assets/images/emoji/suspect.png b/app/assets/images/emoji/suspect.png
new file mode 100755
index 00000000..58e8921c
Binary files /dev/null and b/app/assets/images/emoji/suspect.png differ
diff --git a/app/assets/images/emoji/suspension_railway.png b/app/assets/images/emoji/suspension_railway.png
new file mode 100755
index 00000000..aaa45f61
Binary files /dev/null and b/app/assets/images/emoji/suspension_railway.png differ
diff --git a/app/assets/images/emoji/sweat.png b/app/assets/images/emoji/sweat.png
new file mode 100755
index 00000000..e894b769
Binary files /dev/null and b/app/assets/images/emoji/sweat.png differ
diff --git a/app/assets/images/emoji/sweat_drops.png b/app/assets/images/emoji/sweat_drops.png
new file mode 100755
index 00000000..a83b3e96
Binary files /dev/null and b/app/assets/images/emoji/sweat_drops.png differ
diff --git a/app/assets/images/emoji/sweat_smile.png b/app/assets/images/emoji/sweat_smile.png
new file mode 100755
index 00000000..3903f717
Binary files /dev/null and b/app/assets/images/emoji/sweat_smile.png differ
diff --git a/app/assets/images/emoji/sweet_potato.png b/app/assets/images/emoji/sweet_potato.png
new file mode 100755
index 00000000..32117fa9
Binary files /dev/null and b/app/assets/images/emoji/sweet_potato.png differ
diff --git a/app/assets/images/emoji/swimmer.png b/app/assets/images/emoji/swimmer.png
new file mode 100755
index 00000000..d3878a06
Binary files /dev/null and b/app/assets/images/emoji/swimmer.png differ
diff --git a/app/assets/images/emoji/symbols.png b/app/assets/images/emoji/symbols.png
new file mode 100755
index 00000000..16bc1da9
Binary files /dev/null and b/app/assets/images/emoji/symbols.png differ
diff --git a/app/assets/images/emoji/syringe.png b/app/assets/images/emoji/syringe.png
new file mode 100755
index 00000000..7314255e
Binary files /dev/null and b/app/assets/images/emoji/syringe.png differ
diff --git a/app/assets/images/emoji/tada.png b/app/assets/images/emoji/tada.png
new file mode 100755
index 00000000..7411b526
Binary files /dev/null and b/app/assets/images/emoji/tada.png differ
diff --git a/app/assets/images/emoji/tanabata_tree.png b/app/assets/images/emoji/tanabata_tree.png
new file mode 100755
index 00000000..47334641
Binary files /dev/null and b/app/assets/images/emoji/tanabata_tree.png differ
diff --git a/app/assets/images/emoji/tangerine.png b/app/assets/images/emoji/tangerine.png
new file mode 100755
index 00000000..fc9d4f82
Binary files /dev/null and b/app/assets/images/emoji/tangerine.png differ
diff --git a/app/assets/images/emoji/taurus.png b/app/assets/images/emoji/taurus.png
new file mode 100755
index 00000000..6af582f6
Binary files /dev/null and b/app/assets/images/emoji/taurus.png differ
diff --git a/app/assets/images/emoji/taxi.png b/app/assets/images/emoji/taxi.png
new file mode 100755
index 00000000..60a50d36
Binary files /dev/null and b/app/assets/images/emoji/taxi.png differ
diff --git a/app/assets/images/emoji/tea.png b/app/assets/images/emoji/tea.png
new file mode 100755
index 00000000..3ece0b70
Binary files /dev/null and b/app/assets/images/emoji/tea.png differ
diff --git a/app/assets/images/emoji/telephone.png b/app/assets/images/emoji/telephone.png
new file mode 100755
index 00000000..87d2559b
Binary files /dev/null and b/app/assets/images/emoji/telephone.png differ
diff --git a/app/assets/images/emoji/telephone_receiver.png b/app/assets/images/emoji/telephone_receiver.png
new file mode 100755
index 00000000..36e21e01
Binary files /dev/null and b/app/assets/images/emoji/telephone_receiver.png differ
diff --git a/app/assets/images/emoji/telescope.png b/app/assets/images/emoji/telescope.png
new file mode 100755
index 00000000..51fd8a07
Binary files /dev/null and b/app/assets/images/emoji/telescope.png differ
diff --git a/app/assets/images/emoji/tennis.png b/app/assets/images/emoji/tennis.png
new file mode 100755
index 00000000..278d904e
Binary files /dev/null and b/app/assets/images/emoji/tennis.png differ
diff --git a/app/assets/images/emoji/tent.png b/app/assets/images/emoji/tent.png
new file mode 100755
index 00000000..5c0d20e4
Binary files /dev/null and b/app/assets/images/emoji/tent.png differ
diff --git a/app/assets/images/emoji/thought_balloon.png b/app/assets/images/emoji/thought_balloon.png
new file mode 100755
index 00000000..701bdf0f
Binary files /dev/null and b/app/assets/images/emoji/thought_balloon.png differ
diff --git a/app/assets/images/emoji/three.png b/app/assets/images/emoji/three.png
new file mode 100755
index 00000000..55644c99
Binary files /dev/null and b/app/assets/images/emoji/three.png differ
diff --git a/app/assets/images/emoji/thumbsdown.png b/app/assets/images/emoji/thumbsdown.png
new file mode 100755
index 00000000..41c6b825
Binary files /dev/null and b/app/assets/images/emoji/thumbsdown.png differ
diff --git a/app/assets/images/emoji/thumbsup.png b/app/assets/images/emoji/thumbsup.png
new file mode 100755
index 00000000..81786c1d
Binary files /dev/null and b/app/assets/images/emoji/thumbsup.png differ
diff --git a/app/assets/images/emoji/ticket.png b/app/assets/images/emoji/ticket.png
new file mode 100755
index 00000000..cdacf1a7
Binary files /dev/null and b/app/assets/images/emoji/ticket.png differ
diff --git a/app/assets/images/emoji/tiger.png b/app/assets/images/emoji/tiger.png
new file mode 100755
index 00000000..d6cc84a3
Binary files /dev/null and b/app/assets/images/emoji/tiger.png differ
diff --git a/app/assets/images/emoji/tiger2.png b/app/assets/images/emoji/tiger2.png
new file mode 100755
index 00000000..b0c7d8dc
Binary files /dev/null and b/app/assets/images/emoji/tiger2.png differ
diff --git a/app/assets/images/emoji/tired_face.png b/app/assets/images/emoji/tired_face.png
new file mode 100755
index 00000000..3a8eefe5
Binary files /dev/null and b/app/assets/images/emoji/tired_face.png differ
diff --git a/app/assets/images/emoji/tm.png b/app/assets/images/emoji/tm.png
new file mode 100755
index 00000000..c7dec75a
Binary files /dev/null and b/app/assets/images/emoji/tm.png differ
diff --git a/app/assets/images/emoji/toilet.png b/app/assets/images/emoji/toilet.png
new file mode 100755
index 00000000..e5cc4119
Binary files /dev/null and b/app/assets/images/emoji/toilet.png differ
diff --git a/app/assets/images/emoji/tokyo_tower.png b/app/assets/images/emoji/tokyo_tower.png
new file mode 100755
index 00000000..e1cbd7a3
Binary files /dev/null and b/app/assets/images/emoji/tokyo_tower.png differ
diff --git a/app/assets/images/emoji/tomato.png b/app/assets/images/emoji/tomato.png
new file mode 100755
index 00000000..a129700b
Binary files /dev/null and b/app/assets/images/emoji/tomato.png differ
diff --git a/app/assets/images/emoji/tongue.png b/app/assets/images/emoji/tongue.png
new file mode 100755
index 00000000..333716ee
Binary files /dev/null and b/app/assets/images/emoji/tongue.png differ
diff --git a/app/assets/images/emoji/tongue2.png b/app/assets/images/emoji/tongue2.png
new file mode 100755
index 00000000..b0bab120
Binary files /dev/null and b/app/assets/images/emoji/tongue2.png differ
diff --git a/app/assets/images/emoji/top.png b/app/assets/images/emoji/top.png
new file mode 100755
index 00000000..5aa4dd44
Binary files /dev/null and b/app/assets/images/emoji/top.png differ
diff --git a/app/assets/images/emoji/tophat.png b/app/assets/images/emoji/tophat.png
new file mode 100755
index 00000000..7d27134d
Binary files /dev/null and b/app/assets/images/emoji/tophat.png differ
diff --git a/app/assets/images/emoji/tractor.png b/app/assets/images/emoji/tractor.png
new file mode 100755
index 00000000..058fd3ed
Binary files /dev/null and b/app/assets/images/emoji/tractor.png differ
diff --git a/app/assets/images/emoji/traffic_light.png b/app/assets/images/emoji/traffic_light.png
new file mode 100755
index 00000000..50c78101
Binary files /dev/null and b/app/assets/images/emoji/traffic_light.png differ
diff --git a/app/assets/images/emoji/train.png b/app/assets/images/emoji/train.png
new file mode 100755
index 00000000..3202d80e
Binary files /dev/null and b/app/assets/images/emoji/train.png differ
diff --git a/app/assets/images/emoji/train2.png b/app/assets/images/emoji/train2.png
new file mode 100755
index 00000000..9c0d3ab6
Binary files /dev/null and b/app/assets/images/emoji/train2.png differ
diff --git a/app/assets/images/emoji/tram.png b/app/assets/images/emoji/tram.png
new file mode 100755
index 00000000..5eb29fb7
Binary files /dev/null and b/app/assets/images/emoji/tram.png differ
diff --git a/app/assets/images/emoji/triangular_flag_on_post.png b/app/assets/images/emoji/triangular_flag_on_post.png
new file mode 100755
index 00000000..f9a3f32d
Binary files /dev/null and b/app/assets/images/emoji/triangular_flag_on_post.png differ
diff --git a/app/assets/images/emoji/triangular_ruler.png b/app/assets/images/emoji/triangular_ruler.png
new file mode 100755
index 00000000..383677cb
Binary files /dev/null and b/app/assets/images/emoji/triangular_ruler.png differ
diff --git a/app/assets/images/emoji/trident.png b/app/assets/images/emoji/trident.png
new file mode 100755
index 00000000..d79a7b4c
Binary files /dev/null and b/app/assets/images/emoji/trident.png differ
diff --git a/app/assets/images/emoji/triumph.png b/app/assets/images/emoji/triumph.png
new file mode 100755
index 00000000..92f93bd1
Binary files /dev/null and b/app/assets/images/emoji/triumph.png differ
diff --git a/app/assets/images/emoji/trolleybus.png b/app/assets/images/emoji/trolleybus.png
new file mode 100755
index 00000000..b9740a53
Binary files /dev/null and b/app/assets/images/emoji/trolleybus.png differ
diff --git a/app/assets/images/emoji/trollface.png b/app/assets/images/emoji/trollface.png
new file mode 100755
index 00000000..e234893c
Binary files /dev/null and b/app/assets/images/emoji/trollface.png differ
diff --git a/app/assets/images/emoji/trophy.png b/app/assets/images/emoji/trophy.png
new file mode 100755
index 00000000..95d3b63f
Binary files /dev/null and b/app/assets/images/emoji/trophy.png differ
diff --git a/app/assets/images/emoji/tropical_drink.png b/app/assets/images/emoji/tropical_drink.png
new file mode 100755
index 00000000..55ca9eed
Binary files /dev/null and b/app/assets/images/emoji/tropical_drink.png differ
diff --git a/app/assets/images/emoji/tropical_fish.png b/app/assets/images/emoji/tropical_fish.png
new file mode 100755
index 00000000..a6d73498
Binary files /dev/null and b/app/assets/images/emoji/tropical_fish.png differ
diff --git a/app/assets/images/emoji/truck.png b/app/assets/images/emoji/truck.png
new file mode 100755
index 00000000..3f25ba1f
Binary files /dev/null and b/app/assets/images/emoji/truck.png differ
diff --git a/app/assets/images/emoji/trumpet.png b/app/assets/images/emoji/trumpet.png
new file mode 100755
index 00000000..c84cfb13
Binary files /dev/null and b/app/assets/images/emoji/trumpet.png differ
diff --git a/app/assets/images/emoji/tshirt.png b/app/assets/images/emoji/tshirt.png
new file mode 100755
index 00000000..297a6d63
Binary files /dev/null and b/app/assets/images/emoji/tshirt.png differ
diff --git a/app/assets/images/emoji/tulip.png b/app/assets/images/emoji/tulip.png
new file mode 100755
index 00000000..b3ee1102
Binary files /dev/null and b/app/assets/images/emoji/tulip.png differ
diff --git a/app/assets/images/emoji/turtle.png b/app/assets/images/emoji/turtle.png
new file mode 100755
index 00000000..04d1d968
Binary files /dev/null and b/app/assets/images/emoji/turtle.png differ
diff --git a/app/assets/images/emoji/tv.png b/app/assets/images/emoji/tv.png
new file mode 100755
index 00000000..803dc3d4
Binary files /dev/null and b/app/assets/images/emoji/tv.png differ
diff --git a/app/assets/images/emoji/twisted_rightwards_arrows.png b/app/assets/images/emoji/twisted_rightwards_arrows.png
new file mode 100755
index 00000000..25cde18b
Binary files /dev/null and b/app/assets/images/emoji/twisted_rightwards_arrows.png differ
diff --git a/app/assets/images/emoji/two.png b/app/assets/images/emoji/two.png
new file mode 100755
index 00000000..c191f8a3
Binary files /dev/null and b/app/assets/images/emoji/two.png differ
diff --git a/app/assets/images/emoji/two_hearts.png b/app/assets/images/emoji/two_hearts.png
new file mode 100755
index 00000000..b189e9ae
Binary files /dev/null and b/app/assets/images/emoji/two_hearts.png differ
diff --git a/app/assets/images/emoji/two_men_holding_hands.png b/app/assets/images/emoji/two_men_holding_hands.png
new file mode 100755
index 00000000..d1099f21
Binary files /dev/null and b/app/assets/images/emoji/two_men_holding_hands.png differ
diff --git a/app/assets/images/emoji/two_women_holding_hands.png b/app/assets/images/emoji/two_women_holding_hands.png
new file mode 100755
index 00000000..619646c4
Binary files /dev/null and b/app/assets/images/emoji/two_women_holding_hands.png differ
diff --git a/app/assets/images/emoji/u5272.png b/app/assets/images/emoji/u5272.png
new file mode 100755
index 00000000..2148253f
Binary files /dev/null and b/app/assets/images/emoji/u5272.png differ
diff --git a/app/assets/images/emoji/u5408.png b/app/assets/images/emoji/u5408.png
new file mode 100755
index 00000000..03ab0d87
Binary files /dev/null and b/app/assets/images/emoji/u5408.png differ
diff --git a/app/assets/images/emoji/u55b6.png b/app/assets/images/emoji/u55b6.png
new file mode 100755
index 00000000..ba946d3f
Binary files /dev/null and b/app/assets/images/emoji/u55b6.png differ
diff --git a/app/assets/images/emoji/u6307.png b/app/assets/images/emoji/u6307.png
new file mode 100755
index 00000000..6557f567
Binary files /dev/null and b/app/assets/images/emoji/u6307.png differ
diff --git a/app/assets/images/emoji/u6708.png b/app/assets/images/emoji/u6708.png
new file mode 100755
index 00000000..e4dfe5aa
Binary files /dev/null and b/app/assets/images/emoji/u6708.png differ
diff --git a/app/assets/images/emoji/u6709.png b/app/assets/images/emoji/u6709.png
new file mode 100755
index 00000000..cd8fb3f6
Binary files /dev/null and b/app/assets/images/emoji/u6709.png differ
diff --git a/app/assets/images/emoji/u6e80.png b/app/assets/images/emoji/u6e80.png
new file mode 100755
index 00000000..5df1cb87
Binary files /dev/null and b/app/assets/images/emoji/u6e80.png differ
diff --git a/app/assets/images/emoji/u7121.png b/app/assets/images/emoji/u7121.png
new file mode 100755
index 00000000..25f694ed
Binary files /dev/null and b/app/assets/images/emoji/u7121.png differ
diff --git a/app/assets/images/emoji/u7533.png b/app/assets/images/emoji/u7533.png
new file mode 100755
index 00000000..fc4a9901
Binary files /dev/null and b/app/assets/images/emoji/u7533.png differ
diff --git a/app/assets/images/emoji/u7981.png b/app/assets/images/emoji/u7981.png
new file mode 100755
index 00000000..f550a573
Binary files /dev/null and b/app/assets/images/emoji/u7981.png differ
diff --git a/app/assets/images/emoji/u7a7a.png b/app/assets/images/emoji/u7a7a.png
new file mode 100755
index 00000000..c05f5cff
Binary files /dev/null and b/app/assets/images/emoji/u7a7a.png differ
diff --git a/app/assets/images/emoji/uk.png b/app/assets/images/emoji/uk.png
new file mode 100755
index 00000000..2a62c7a0
Binary files /dev/null and b/app/assets/images/emoji/uk.png differ
diff --git a/app/assets/images/emoji/umbrella.png b/app/assets/images/emoji/umbrella.png
new file mode 100755
index 00000000..1db722fa
Binary files /dev/null and b/app/assets/images/emoji/umbrella.png differ
diff --git a/app/assets/images/emoji/unamused.png b/app/assets/images/emoji/unamused.png
new file mode 100755
index 00000000..3722e6f5
Binary files /dev/null and b/app/assets/images/emoji/unamused.png differ
diff --git a/app/assets/images/emoji/underage.png b/app/assets/images/emoji/underage.png
new file mode 100755
index 00000000..a789b3c6
Binary files /dev/null and b/app/assets/images/emoji/underage.png differ
diff --git a/app/assets/images/emoji/unlock.png b/app/assets/images/emoji/unlock.png
new file mode 100755
index 00000000..22b429cd
Binary files /dev/null and b/app/assets/images/emoji/unlock.png differ
diff --git a/app/assets/images/emoji/up.png b/app/assets/images/emoji/up.png
new file mode 100755
index 00000000..829219a8
Binary files /dev/null and b/app/assets/images/emoji/up.png differ
diff --git a/app/assets/images/emoji/us.png b/app/assets/images/emoji/us.png
new file mode 100755
index 00000000..38137669
Binary files /dev/null and b/app/assets/images/emoji/us.png differ
diff --git a/app/assets/images/emoji/v.png b/app/assets/images/emoji/v.png
new file mode 100755
index 00000000..f61267c2
Binary files /dev/null and b/app/assets/images/emoji/v.png differ
diff --git a/app/assets/images/emoji/vertical_traffic_light.png b/app/assets/images/emoji/vertical_traffic_light.png
new file mode 100755
index 00000000..7a5ba35f
Binary files /dev/null and b/app/assets/images/emoji/vertical_traffic_light.png differ
diff --git a/app/assets/images/emoji/vhs.png b/app/assets/images/emoji/vhs.png
new file mode 100755
index 00000000..881081c1
Binary files /dev/null and b/app/assets/images/emoji/vhs.png differ
diff --git a/app/assets/images/emoji/vibration_mode.png b/app/assets/images/emoji/vibration_mode.png
new file mode 100755
index 00000000..a716e96c
Binary files /dev/null and b/app/assets/images/emoji/vibration_mode.png differ
diff --git a/app/assets/images/emoji/video_camera.png b/app/assets/images/emoji/video_camera.png
new file mode 100755
index 00000000..274cecdd
Binary files /dev/null and b/app/assets/images/emoji/video_camera.png differ
diff --git a/app/assets/images/emoji/video_game.png b/app/assets/images/emoji/video_game.png
new file mode 100755
index 00000000..59d45bae
Binary files /dev/null and b/app/assets/images/emoji/video_game.png differ
diff --git a/app/assets/images/emoji/violin.png b/app/assets/images/emoji/violin.png
new file mode 100755
index 00000000..0dba5ba2
Binary files /dev/null and b/app/assets/images/emoji/violin.png differ
diff --git a/app/assets/images/emoji/virgo.png b/app/assets/images/emoji/virgo.png
new file mode 100755
index 00000000..72e1763f
Binary files /dev/null and b/app/assets/images/emoji/virgo.png differ
diff --git a/app/assets/images/emoji/volcano.png b/app/assets/images/emoji/volcano.png
new file mode 100755
index 00000000..9b434539
Binary files /dev/null and b/app/assets/images/emoji/volcano.png differ
diff --git a/app/assets/images/emoji/vs.png b/app/assets/images/emoji/vs.png
new file mode 100755
index 00000000..86363885
Binary files /dev/null and b/app/assets/images/emoji/vs.png differ
diff --git a/app/assets/images/emoji/walking.png b/app/assets/images/emoji/walking.png
new file mode 100755
index 00000000..52bc0381
Binary files /dev/null and b/app/assets/images/emoji/walking.png differ
diff --git a/app/assets/images/emoji/waning_crescent_moon.png b/app/assets/images/emoji/waning_crescent_moon.png
new file mode 100755
index 00000000..30387780
Binary files /dev/null and b/app/assets/images/emoji/waning_crescent_moon.png differ
diff --git a/app/assets/images/emoji/waning_gibbous_moon.png b/app/assets/images/emoji/waning_gibbous_moon.png
new file mode 100755
index 00000000..8e324ec5
Binary files /dev/null and b/app/assets/images/emoji/waning_gibbous_moon.png differ
diff --git a/app/assets/images/emoji/warning.png b/app/assets/images/emoji/warning.png
new file mode 100755
index 00000000..466658d9
Binary files /dev/null and b/app/assets/images/emoji/warning.png differ
diff --git a/app/assets/images/emoji/watch.png b/app/assets/images/emoji/watch.png
new file mode 100755
index 00000000..d503bb87
Binary files /dev/null and b/app/assets/images/emoji/watch.png differ
diff --git a/app/assets/images/emoji/water_buffalo.png b/app/assets/images/emoji/water_buffalo.png
new file mode 100755
index 00000000..3bcde3ed
Binary files /dev/null and b/app/assets/images/emoji/water_buffalo.png differ
diff --git a/app/assets/images/emoji/watermelon.png b/app/assets/images/emoji/watermelon.png
new file mode 100755
index 00000000..fc212be7
Binary files /dev/null and b/app/assets/images/emoji/watermelon.png differ
diff --git a/app/assets/images/emoji/wave.png b/app/assets/images/emoji/wave.png
new file mode 100755
index 00000000..e78402eb
Binary files /dev/null and b/app/assets/images/emoji/wave.png differ
diff --git a/app/assets/images/emoji/wavy_dash.png b/app/assets/images/emoji/wavy_dash.png
new file mode 100755
index 00000000..77f626cc
Binary files /dev/null and b/app/assets/images/emoji/wavy_dash.png differ
diff --git a/app/assets/images/emoji/waxing_crescent_moon.png b/app/assets/images/emoji/waxing_crescent_moon.png
new file mode 100755
index 00000000..c8f13dd3
Binary files /dev/null and b/app/assets/images/emoji/waxing_crescent_moon.png differ
diff --git a/app/assets/images/emoji/waxing_gibbous_moon.png b/app/assets/images/emoji/waxing_gibbous_moon.png
new file mode 100755
index 00000000..dd8c4845
Binary files /dev/null and b/app/assets/images/emoji/waxing_gibbous_moon.png differ
diff --git a/app/assets/images/emoji/wc.png b/app/assets/images/emoji/wc.png
new file mode 100755
index 00000000..dfe84d2a
Binary files /dev/null and b/app/assets/images/emoji/wc.png differ
diff --git a/app/assets/images/emoji/weary.png b/app/assets/images/emoji/weary.png
new file mode 100755
index 00000000..0c547541
Binary files /dev/null and b/app/assets/images/emoji/weary.png differ
diff --git a/app/assets/images/emoji/wedding.png b/app/assets/images/emoji/wedding.png
new file mode 100755
index 00000000..ead19d52
Binary files /dev/null and b/app/assets/images/emoji/wedding.png differ
diff --git a/app/assets/images/emoji/whale.png b/app/assets/images/emoji/whale.png
new file mode 100755
index 00000000..5bb113e4
Binary files /dev/null and b/app/assets/images/emoji/whale.png differ
diff --git a/app/assets/images/emoji/whale2.png b/app/assets/images/emoji/whale2.png
new file mode 100755
index 00000000..4af657b2
Binary files /dev/null and b/app/assets/images/emoji/whale2.png differ
diff --git a/app/assets/images/emoji/wheelchair.png b/app/assets/images/emoji/wheelchair.png
new file mode 100755
index 00000000..eddcdd79
Binary files /dev/null and b/app/assets/images/emoji/wheelchair.png differ
diff --git a/app/assets/images/emoji/white_circle.png b/app/assets/images/emoji/white_circle.png
new file mode 100755
index 00000000..da782ae2
Binary files /dev/null and b/app/assets/images/emoji/white_circle.png differ
diff --git a/app/assets/images/emoji/white_flower.png b/app/assets/images/emoji/white_flower.png
new file mode 100755
index 00000000..c0929d0d
Binary files /dev/null and b/app/assets/images/emoji/white_flower.png differ
diff --git a/app/assets/images/emoji/white_square.png b/app/assets/images/emoji/white_square.png
new file mode 100755
index 00000000..60cb19a1
Binary files /dev/null and b/app/assets/images/emoji/white_square.png differ
diff --git a/app/assets/images/emoji/wind_chime.png b/app/assets/images/emoji/wind_chime.png
new file mode 100755
index 00000000..efacf5dd
Binary files /dev/null and b/app/assets/images/emoji/wind_chime.png differ
diff --git a/app/assets/images/emoji/wine_glass.png b/app/assets/images/emoji/wine_glass.png
new file mode 100755
index 00000000..82b0f000
Binary files /dev/null and b/app/assets/images/emoji/wine_glass.png differ
diff --git a/app/assets/images/emoji/wink.png b/app/assets/images/emoji/wink.png
new file mode 100755
index 00000000..756766dd
Binary files /dev/null and b/app/assets/images/emoji/wink.png differ
diff --git a/app/assets/images/emoji/wink2.png b/app/assets/images/emoji/wink2.png
new file mode 100755
index 00000000..6ae9d497
Binary files /dev/null and b/app/assets/images/emoji/wink2.png differ
diff --git a/app/assets/images/emoji/wolf.png b/app/assets/images/emoji/wolf.png
new file mode 100755
index 00000000..c60c9689
Binary files /dev/null and b/app/assets/images/emoji/wolf.png differ
diff --git a/app/assets/images/emoji/woman.png b/app/assets/images/emoji/woman.png
new file mode 100755
index 00000000..6bf0d2b1
Binary files /dev/null and b/app/assets/images/emoji/woman.png differ
diff --git a/app/assets/images/emoji/womans_clothes.png b/app/assets/images/emoji/womans_clothes.png
new file mode 100755
index 00000000..aa297c7b
Binary files /dev/null and b/app/assets/images/emoji/womans_clothes.png differ
diff --git a/app/assets/images/emoji/womans_hat.png b/app/assets/images/emoji/womans_hat.png
new file mode 100755
index 00000000..4cb2e6a6
Binary files /dev/null and b/app/assets/images/emoji/womans_hat.png differ
diff --git a/app/assets/images/emoji/womens.png b/app/assets/images/emoji/womens.png
new file mode 100755
index 00000000..110f8851
Binary files /dev/null and b/app/assets/images/emoji/womens.png differ
diff --git a/app/assets/images/emoji/wrench.png b/app/assets/images/emoji/wrench.png
new file mode 100755
index 00000000..a87072ad
Binary files /dev/null and b/app/assets/images/emoji/wrench.png differ
diff --git a/app/assets/images/emoji/x.png b/app/assets/images/emoji/x.png
new file mode 100755
index 00000000..dff9efa8
Binary files /dev/null and b/app/assets/images/emoji/x.png differ
diff --git a/app/assets/images/emoji/yellow_heart.png b/app/assets/images/emoji/yellow_heart.png
new file mode 100755
index 00000000..fa41ce78
Binary files /dev/null and b/app/assets/images/emoji/yellow_heart.png differ
diff --git a/app/assets/images/emoji/yen.png b/app/assets/images/emoji/yen.png
new file mode 100755
index 00000000..139bc936
Binary files /dev/null and b/app/assets/images/emoji/yen.png differ
diff --git a/app/assets/images/emoji/yum.png b/app/assets/images/emoji/yum.png
new file mode 100755
index 00000000..fc39637e
Binary files /dev/null and b/app/assets/images/emoji/yum.png differ
diff --git a/app/assets/images/emoji/zap.png b/app/assets/images/emoji/zap.png
new file mode 100755
index 00000000..260c531b
Binary files /dev/null and b/app/assets/images/emoji/zap.png differ
diff --git a/app/assets/images/emoji/zero.png b/app/assets/images/emoji/zero.png
new file mode 100755
index 00000000..6e57b334
Binary files /dev/null and b/app/assets/images/emoji/zero.png differ
diff --git a/app/assets/images/emoji/zzz.png b/app/assets/images/emoji/zzz.png
new file mode 100755
index 00000000..30be0465
Binary files /dev/null and b/app/assets/images/emoji/zzz.png differ
diff --git a/app/assets/images/file_dir.png b/app/assets/images/file_dir.png
index 97b05393..ea277bb1 100644
Binary files a/app/assets/images/file_dir.png and b/app/assets/images/file_dir.png differ
diff --git a/app/assets/images/merge.png b/app/assets/images/merge.png
new file mode 100644
index 00000000..4a6bb2e1
Binary files /dev/null and b/app/assets/images/merge.png differ
diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js
deleted file mode 100644
index bb0a499a..00000000
--- a/app/assets/javascripts/admin.js
+++ /dev/null
@@ -1,11 +0,0 @@
-$(document).ready(function(){
- $('input#user_force_random_password').on('change', function(elem) {
- var elems = $('#user_password, #user_password_confirmation');
-
- if ($(this).attr('checked')) {
- elems.val('').attr('disabled', true);
- } else {
- elems.removeAttr('disabled');
- }
- });
-});
diff --git a/app/assets/javascripts/admin.js.coffee b/app/assets/javascripts/admin.js.coffee
new file mode 100644
index 00000000..76454c29
--- /dev/null
+++ b/app/assets/javascripts/admin.js.coffee
@@ -0,0 +1,12 @@
+$ ->
+ $('input#user_force_random_password').on 'change', (elem) ->
+ elems = $('#user_password, #user_password_confirmation')
+
+ if $(@).attr 'checked'
+ elems.val('').attr 'disabled', true
+ else
+ elems.removeAttr 'disabled'
+
+ $('.log-tabs a').click (e) ->
+ e.preventDefault()
+ $(this).tab('show')
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 24d99a62..f9fdb0f7 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -11,120 +11,9 @@
//= require jquery.endless-scroll
//= require jquery.highlight
//= require jquery.waitforimages
-//= require bootstrap-modal
+//= require bootstrap
//= require modernizr
//= require chosen-jquery
//= require raphael
//= require branch-graph
//= require_tree .
-
-$(document).ready(function(){
-
- $(".one_click_select").live("click", function(){
- $(this).select();
- });
-
- $('body').on('ajax:complete, ajax:beforeSend, submit', 'form', function(e){
- var buttons = $('[type="submit"]', this);
- switch( e.type ){
- case 'ajax:beforeSend':
- case 'submit':
- buttons.attr('disabled', 'disabled');
- break;
- case ' ajax:complete':
- default:
- buttons.removeAttr('disabled');
- break;
- }
- })
-
- $(".account-box").mouseenter(showMenu);
- $(".account-box").mouseleave(resetMenu);
-
- $("#projects-list .project").live('click', function(e){
- if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {
- location.href = $(this).attr("url");
- e.stopPropagation();
- return false;
- }
- });
-
- /**
- * Focus search field by pressing 's' key
- */
- $(document).keypress(function(e) {
- if( $(e.target).is(":input") ) return;
- switch(e.which) {
- case 115: focusSearch();
- e.preventDefault();
- }
- });
-
- /**
- * Commit show suppressed diff
- *
- */
- $(".supp_diff_link").bind("click", function() {
- showDiff(this);
- });
-
- /**
- * Note markdown preview
- *
- */
- $(document).on('click', '#preview-link', function(e) {
- $('#preview-note').text('Loading...');
-
- var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview');
- $(this).text(previewLinkText);
-
- var note = $('#note_note').val();
- if (note.trim().length === 0) { note = 'Nothing to preview'; }
- $.post($(this).attr('href'), {note: note}, function(data) {
- $('#preview-note').html(data);
- });
-
- $('#preview-note, #note_note').toggle();
- e.preventDefault();
- });
-});
-
-function focusSearch() {
- $("#search").focus();
-}
-
-function updatePage(data){
- $.ajax({type: "GET", url: location.href, data: data, dataType: "script"});
-}
-
-function showMenu() {
- $(this).toggleClass('hover');
-}
-
-function resetMenu() {
- $(this).removeClass("hover");
-}
-
-function slugify(text) {
- return text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase();
-}
-
-function showDiff(link) {
- $(link).next('table').show();
- $(link).remove();
-}
-
-(function($){
- var _chosen = $.fn.chosen;
- $.fn.extend({
- chosen: function(options) {
- var default_options = {'search_contains' : 'true'};
- $.extend(default_options, options);
- return _chosen.apply(this, [default_options]);
- }})
-})(jQuery);
-
-
-function ajaxGet(url) {
- $.ajax({type: "GET", url: url, dataType: "script"});
-}
diff --git a/app/assets/javascripts/graph.js b/app/assets/javascripts/graph.js
deleted file mode 100644
index 434cf70a..00000000
--- a/app/assets/javascripts/graph.js
+++ /dev/null
@@ -1,10 +0,0 @@
-function initGraphNav() {
- $(".graph svg").css("position", "relative");
- $("body").bind("keyup", function(e) {
- if(e.keyCode == 37) { // left
- $(".graph svg").animate({ left: "+=400" });
- } else if(e.keyCode == 39) { // right
- $(".graph svg").animate({ left: "-=400" });
- }
- });
-}
diff --git a/app/assets/javascripts/graph.js.coffee b/app/assets/javascripts/graph.js.coffee
new file mode 100644
index 00000000..5fe8ae3f
--- /dev/null
+++ b/app/assets/javascripts/graph.js.coffee
@@ -0,0 +1,10 @@
+initGraphNav = ->
+ $('.graph svg').css 'position', 'relative'
+
+ $('body').bind 'keyup', (e) ->
+ if e.keyCode is 37 # left
+ $('.graph svg').animate left: '+=400'
+ else if e.keyCode is 39 # right
+ $('.graph svg').animate left: '-=400'
+
+window.initGraphNav = initGraphNav
diff --git a/app/assets/javascripts/issues.js b/app/assets/javascripts/issues.js
index bc056965..3ddc6926 100644
--- a/app/assets/javascripts/issues.js
+++ b/app/assets/javascripts/issues.js
@@ -5,6 +5,7 @@ function switchToNewIssue(form){
$('select#issue_milestone_id').chosen();
$("#new_issue_dialog").show("fade", { direction: "right" }, 150);
$('.top-tabs .add_new').hide();
+ disableButtonIfEmptyField("#issue_title", ".save-btn");
});
}
@@ -15,6 +16,7 @@ function switchToEditIssue(form){
$('select#issue_milestone_id').chosen();
$("#edit_issue_dialog").show("fade", { direction: "right" }, 150);
$('.add_new').hide();
+ disableButtonIfEmptyField("#issue_title", ".save-btn");
});
}
@@ -78,6 +80,10 @@ function issuesPage(){
$(this).closest("form").submit();
});
+ $("#new_issue_link").click(function(){
+ updateNewIssueURL();
+ });
+
$('body').on('ajax:success', '.close_issue, .reopen_issue, #new_issue', function(){
var t = $(this),
totalIssues,
@@ -124,3 +130,20 @@ function issuesCheckChanged() {
$('.issues_filters').show();
}
}
+
+function updateNewIssueURL(){
+ var new_issue_link = $("#new_issue_link");
+ var milestone_id = $("#milestone_id").val();
+ var assignee_id = $("#assignee_id").val();
+ var new_href = "";
+ if(milestone_id){
+ new_href = "issue[milestone_id]=" + milestone_id + "&";
+ }
+ if(assignee_id){
+ new_href = new_href + "issue[assignee_id]=" + assignee_id;
+ }
+ if(new_href.length){
+ new_href = new_issue_link.attr("href") + "?" + new_href;
+ new_issue_link.attr("href", new_href);
+ }
+};
diff --git a/app/assets/javascripts/loader.js b/app/assets/javascripts/loader.js
deleted file mode 100644
index 6fa0b525..00000000
--- a/app/assets/javascripts/loader.js
+++ /dev/null
@@ -1,11 +0,0 @@
-var Loader = {
- img_src: "/assets/ajax-loader.gif",
-
- html:
- function(width) {
- img = $("");
- img.attr("width", width);
- img.attr("src", this.img_src);
- return img;
- }
-}
diff --git a/app/assets/javascripts/loader.js.coffee b/app/assets/javascripts/loader.js.coffee
new file mode 100644
index 00000000..66f8e8b1
--- /dev/null
+++ b/app/assets/javascripts/loader.js.coffee
@@ -0,0 +1,5 @@
+Loader =
+ html: (width) ->
+ $('
').attr src: '/assets/ajax-loader.gif', width: width
+
+window.Loader = Loader
diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee
new file mode 100644
index 00000000..86b19162
--- /dev/null
+++ b/app/assets/javascripts/main.js.coffee
@@ -0,0 +1,92 @@
+window.updatePage = (data) ->
+ $.ajax({type: "GET", url: location.href, data: data, dataType: "script"})
+
+window.slugify = (text) ->
+ text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
+
+window.ajaxGet = (url) ->
+ $.ajax({type: "GET", url: url, dataType: "script"})
+
+ # Disable button if text field is empty
+window.disableButtonIfEmptyField = (field_selector, button_selector) ->
+ field = $(field_selector)
+ closest_submit = field.closest("form").find(button_selector)
+
+ closest_submit.disable() if field.val() is ""
+
+ field.on "keyup", ->
+ if $(this).val() is ""
+ closest_submit.disable()
+ else
+ closest_submit.enable()
+
+$ ->
+ # Click a .one_click_select field, select the contents
+ $(".one_click_select").live 'click', -> $(this).select()
+
+ # Initialize chosen selects
+ $('select.chosen').chosen()
+
+ # Disable form buttons while a form is submitting
+ $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) ->
+ buttons = $('[type="submit"]', this)
+
+ switch e.type
+ when 'ajax:beforeSend', 'submit'
+ buttons.disable()
+ else
+ buttons.enable()
+
+ # Show/Hide the profile menu when hovering the account box
+ $('.account-box').hover -> $(this).toggleClass('hover')
+
+ # Focus search field by pressing 's' key
+ $(document).keypress (e) ->
+ # Don't do anything if typing in an input
+ return if $(e.target).is(":input")
+
+ switch e.which
+ when 115
+ $("#search").focus()
+ e.preventDefault()
+
+ # Commit show suppressed diff
+ $(".supp_diff_link").bind "click", ->
+ $(this).next('table').show()
+ $(this).remove()
+
+ # Note markdown preview
+ $(document).on 'click', '#preview-link', (e) ->
+ $('#preview-note').text('Loading...')
+
+ previewLinkText = if $(this).text() == 'Preview' then 'Edit' else 'Preview'
+ $(this).text(previewLinkText)
+
+ note = $('#note_note').val()
+
+ if note.trim().length == 0
+ $('#preview-note').text("Nothing to preview.")
+ else
+ $.post $(this).attr('href'), {note: note}, (data) ->
+ $('#preview-note').html(data)
+
+ $('#preview-note, #note_note').toggle()
+ e.preventDefault()
+ false
+
+(($) ->
+ _chosen = $.fn.chosen
+ $.fn.extend chosen: (options) ->
+ default_options = search_contains: "true"
+ $.extend default_options, options
+ _chosen.apply this, [default_options]
+
+ # Disable an element and add the 'disabled' Bootstrap class
+ $.fn.extend disable: ->
+ $(this).attr('disabled', 'disabled').addClass('disabled')
+
+ # Enable an element and remove the 'disabled' Bootstrap class
+ $.fn.extend enable: ->
+ $(this).removeAttr('disabled').removeClass('disabled')
+
+)(jQuery)
diff --git a/app/assets/javascripts/note.js b/app/assets/javascripts/note.js
deleted file mode 100644
index d9ae45d9..00000000
--- a/app/assets/javascripts/note.js
+++ /dev/null
@@ -1,169 +0,0 @@
-var NoteList = {
-
-notes_path: null,
-target_params: null,
-target_id: 0,
-target_type: null,
-first_id: 0,
-last_id: 0,
-disable:false,
-
-init:
- function(tid, tt, path) {
- this.notes_path = path + ".js";
- this.target_id = tid;
- this.target_type = tt;
- this.target_params = "&target_type=" + this.target_type + "&target_id=" + this.target_id;
-
- // get notes
- this.getContent();
-
- // get new notes every n seconds
- this.initRefresh();
-
- $('.delete-note').live('ajax:success', function() {
- $(this).closest('li').fadeOut(); });
-
- $("#new_note").live("ajax:before", function(){
- $(".submit_note").attr("disabled", "disabled");
- })
-
- $("#new_note").live("ajax:complete", function(){
- $(".submit_note").removeAttr("disabled");
- })
-
- $("#note_note").live("focus", function(){
- $(this).css("height", "80px");
- $('.note_advanced_opts').show();
- });
-
- $("#note_attachment").change(function(e){
- var val = $('.input-file').val();
- var filename = val.replace(/^.*[\\\/]/, '');
- $(".file_name").text(filename);
- });
-
- },
-
-
-/**
- * Load new notes to fresh list called 'new_notes_list':
- * - Replace 'new_notes_list' with new list every n seconds
- * - Append new notes to this list after submit
- */
-
-initRefresh:
- function() {
- // init timer
- var intNew = setInterval("NoteList.getNew()", 10000);
- },
-
-replace:
- function(html) {
- $("#new_notes_list").html(html);
- },
-
-prepend:
- function(id, html) {
- if(id != this.last_id) {
- $("#new_notes_list").prepend(html);
- }
- },
-
-getNew:
- function() {
- // refersh notes list
- $.ajax({
- type: "GET",
- url: this.notes_path,
- data: "last_id=" + this.last_id + this.target_params,
- dataType: "script"});
- },
-
-refresh:
- function() {
- // refersh notes list
- $.ajax({
- type: "GET",
- url: this.notes_path,
- data: "first_id=" + this.first_id + "&last_id=" + this.last_id + this.target_params,
- dataType: "script"});
- },
-
-
-/**
- * Init load of notes:
- * 1. Get content with ajax call
- * 2. Set content of notes list with loaded one
- */
-
-
-getContent:
- function() {
- $.ajax({
- type: "GET",
- url: this.notes_path,
- data: "?" + this.target_params,
- complete: function(){ $('.status').removeClass("loading")},
- beforeSend: function() { $('.status').addClass("loading") },
- dataType: "script"});
- },
-
-setContent:
- function(fid, lid, html) {
- this.last_id = lid;
- this.first_id = fid;
- $("#notes-list").html(html);
-
- // Init infinite scrolling
- this.initLoadMore();
- },
-
-
-/**
- * Paging for old notes when scroll to bottom:
- * 1. Init scroll events with 'initLoadMore'
- * 2. Load onlder notes with 'getOld' method
- * 3. append old notes to bottom of list with 'append'
- *
- */
-
-
-getOld:
- function() {
- $('.loading').show();
- $.ajax({
- type: "GET",
- url: this.notes_path,
- data: "first_id=" + this.first_id + this.target_params,
- complete: function(){ $('.status').removeClass("loading")},
- beforeSend: function() { $('.status').addClass("loading") },
- dataType: "script"});
- },
-
-append:
- function(id, html) {
- if(this.first_id == id) {
- this.disable = true;
- } else {
- this.first_id = id;
- $("#notes-list").append(html);
- }
- },
-
-
-initLoadMore:
- function() {
- $(document).endlessScroll({
- bottomPixels: 400,
- fireDelay: 1000,
- fireOnce:true,
- ceaseFire: function() {
- return NoteList.disable;
- },
- callback: function(i) {
- NoteList.getOld();
- }
- });
- }
-}
diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js
new file mode 100644
index 00000000..e1ad1d2f
--- /dev/null
+++ b/app/assets/javascripts/notes.js
@@ -0,0 +1,293 @@
+var NoteList = {
+
+ notes_path: null,
+ target_params: null,
+ target_id: 0,
+ target_type: null,
+ top_id: 0,
+ bottom_id: 0,
+ loading_more_disabled: false,
+ reversed: false,
+
+ init:
+ function(tid, tt, path) {
+ this.notes_path = path + ".js";
+ this.target_id = tid;
+ this.target_type = tt;
+ this.reversed = $("#notes-list").hasClass("reversed");
+ this.target_params = "&target_type=" + this.target_type + "&target_id=" + this.target_id;
+
+ // get initial set of notes
+ this.getContent();
+
+ $("#notes-list, #new-notes-list").on("ajax:success", ".delete-note", function() {
+ $(this).closest('li').fadeOut(function() {
+ $(this).remove();
+ NoteList.updateVotes();
+ });
+ });
+
+ $(".note-form-holder").on("ajax:before", function(){
+ $(".submit_note").disable();
+ })
+
+ $(".note-form-holder").on("ajax:complete", function(){
+ $(".submit_note").enable();
+ })
+
+ disableButtonIfEmptyField(".note-text", ".submit_note");
+
+ $("#note_attachment").change(function(e){
+ var val = $('.input-file').val();
+ var filename = val.replace(/^.*[\\\/]/, '');
+ $(".file_name").text(filename);
+ });
+
+ if(this.reversed) {
+ var textarea = $(".note-text");
+ $('.note_advanced_opts').hide();
+ textarea.css("height", "40px");
+ textarea.on("focus", function(){
+ $(this).css("height", "80px");
+ $('.note_advanced_opts').show();
+ });
+ }
+ },
+
+
+ /**
+ * Handle loading the initial set of notes.
+ * And set up loading more notes when scrolling to the bottom of the page.
+ */
+
+
+ /**
+ * Gets an inital set of notes.
+ */
+ getContent:
+ function() {
+ $.ajax({
+ type: "GET",
+ url: this.notes_path,
+ data: "?" + this.target_params,
+ complete: function(){ $('.notes-status').removeClass("loading")},
+ beforeSend: function() { $('.notes-status').addClass("loading") },
+ dataType: "script"});
+ },
+
+ /**
+ * Called in response to getContent().
+ * Replaces the content of #notes-list with the given html.
+ */
+ setContent:
+ function(first_id, last_id, html) {
+ this.top_id = first_id;
+ this.bottom_id = last_id;
+ $("#notes-list").html(html);
+
+ // init infinite scrolling
+ this.initLoadMore();
+
+ // init getting new notes
+ if (this.reversed) {
+ this.initRefreshNew();
+ }
+ },
+
+
+ /**
+ * Handle loading more notes when scrolling to the bottom of the page.
+ * The id of the last note in the list is in this.bottom_id.
+ *
+ * Set up refreshing only new notes after all notes have been loaded.
+ */
+
+
+ /**
+ * Initializes loading more notes when scrolling to the bottom of the page.
+ */
+ initLoadMore:
+ function() {
+ $(document).endlessScroll({
+ bottomPixels: 400,
+ fireDelay: 1000,
+ fireOnce:true,
+ ceaseFire: function() {
+ return NoteList.loading_more_disabled;
+ },
+ callback: function(i) {
+ NoteList.getMore();
+ }
+ });
+ },
+
+ /**
+ * Gets an additional set of notes.
+ */
+ getMore:
+ function() {
+ // only load more notes if there are no "new" notes
+ $('.loading').show();
+ $.ajax({
+ type: "GET",
+ url: this.notes_path,
+ data: "loading_more=1&" + (this.reversed ? "before_id" : "after_id") + "=" + this.bottom_id + this.target_params,
+ complete: function(){ $('.notes-status').removeClass("loading")},
+ beforeSend: function() { $('.notes-status').addClass("loading") },
+ dataType: "script"});
+ },
+
+ /**
+ * Called in response to getMore().
+ * Append notes to #notes-list.
+ */
+ appendMoreNotes:
+ function(id, html) {
+ if(id != this.bottom_id) {
+ this.bottom_id = id;
+ $("#notes-list").append(html);
+ }
+ },
+
+ /**
+ * Called in response to getMore().
+ * Disables loading more notes when scrolling to the bottom of the page.
+ * Initalizes refreshing new notes.
+ */
+ finishedLoadingMore:
+ function() {
+ this.loading_more_disabled = true;
+
+ // from now on only get new notes
+ if (!this.reversed) {
+ this.initRefreshNew();
+ }
+ // make sure we are up to date
+ this.updateVotes();
+ },
+
+
+ /**
+ * Handle refreshing and adding of new notes.
+ *
+ * New notes are all notes that are created after the site has been loaded.
+ * The "old" notes are in #notes-list the "new" ones will be in #new-notes-list.
+ * The id of the last "old" note is in this.bottom_id.
+ */
+
+
+ /**
+ * Initializes getting new notes every n seconds.
+ */
+ initRefreshNew:
+ function() {
+ setInterval("NoteList.getNew()", 10000);
+ },
+
+ /**
+ * Gets the new set of notes.
+ */
+ getNew:
+ function() {
+ $.ajax({
+ type: "GET",
+ url: this.notes_path,
+ data: "loading_new=1&after_id=" + (this.reversed ? this.top_id : this.bottom_id) + this.target_params,
+ dataType: "script"});
+ },
+
+ /**
+ * Called in response to getNew().
+ * Replaces the content of #new-notes-list with the given html.
+ */
+ replaceNewNotes:
+ function(html) {
+ $("#new-notes-list").html(html);
+ this.updateVotes();
+ },
+
+ /**
+ * Adds a single note to #new-notes-list.
+ */
+ appendNewNote:
+ function(id, html) {
+ if (this.reversed) {
+ $("#new-notes-list").prepend(html);
+ } else {
+ $("#new-notes-list").append(html);
+ }
+ this.updateVotes();
+ },
+
+ /**
+ * Recalculates the votes and updates them (if they are displayed at all).
+ *
+ * Assumes all relevant notes are displayed (i.e. there are no more notes to
+ * load via getMore()).
+ * Might produce inaccurate results when not all notes have been loaded and a
+ * recalculation is triggered (e.g. when deleting a note).
+ */
+ updateVotes:
+ function() {
+ var votes = $("#votes .votes");
+ var notes = $("#notes-list, #new-notes-list").find(".note.vote");
+
+ // only update if there is a vote display
+ if (votes.size()) {
+ var upvotes = notes.filter(".upvote").size();
+ var downvotes = notes.filter(".downvote").size();
+ var votesCount = upvotes + downvotes;
+ var upvotesPercent = votesCount ? (100.0 / votesCount * upvotes) : 0;
+ var downvotesPercent = votesCount ? (100.0 - upvotesPercent) : 0;
+
+ // change vote bar lengths
+ votes.find(".bar-success").css("width", upvotesPercent+"%");
+ votes.find(".bar-danger").css("width", downvotesPercent+"%");
+ // replace vote numbers
+ votes.find(".upvotes").text(votes.find(".upvotes").text().replace(/\d+/, upvotes));
+ votes.find(".downvotes").text(votes.find(".downvotes").text().replace(/\d+/, downvotes));
+ }
+ }
+};
+
+var PerLineNotes = {
+ init:
+ function() {
+ /**
+ * Called when clicking on the "add note" or "reply" button for a diff line.
+ *
+ * Shows the note form below the line.
+ * Sets some hidden fields in the form.
+ */
+ $(".diff_file_content").on("click", ".line_note_link, .line_note_reply_link", function(e) {
+ var form = $(".per_line_form");
+ $(this).closest("tr").after(form);
+ form.find("#note_line_code").val($(this).data("lineCode"));
+ form.show();
+ return false;
+ });
+
+ disableButtonIfEmptyField(".line-note-text", ".submit_inline_note");
+
+ /**
+ * Called in response to successfully deleting a note on a diff line.
+ *
+ * Removes the actual note from view.
+ * Removes the reply button if the last note for that line has been removed.
+ */
+ $(".diff_file_content").on("ajax:success", ".delete-note", function() {
+ var trNote = $(this).closest("tr");
+ trNote.fadeOut(function() {
+ $(this).remove();
+ });
+
+ // check if this is the last note for this line
+ // elements must really be removed for this to work reliably
+ var trLine = trNote.prev();
+ var trRpl = trNote.next();
+ if (trLine.hasClass("line_holder") && trRpl.hasClass("reply")) {
+ trRpl.fadeOut(function() { $(this).remove(); });
+ }
+ });
+ }
+}
diff --git a/app/assets/javascripts/projects.js b/app/assets/javascripts/projects.js
deleted file mode 100644
index 84272698..00000000
--- a/app/assets/javascripts/projects.js
+++ /dev/null
@@ -1,14 +0,0 @@
-function Projects() {
- $("#project_name").live("change", function(){
- var slug = slugify($(this).val());
- $("#project_code").val(slug);
- $("#project_path").val(slug);
- });
-
- $('.new_project, .edit_project').live('ajax:before', function() {
- $('.project_new_holder, .project_edit_holder').hide();
- $('.ajax_loader').show();
- });
-
- $('form #project_default_branch').chosen();
-}
diff --git a/app/assets/javascripts/projects.js.coffee b/app/assets/javascripts/projects.js.coffee
new file mode 100644
index 00000000..008fa8e9
--- /dev/null
+++ b/app/assets/javascripts/projects.js.coffee
@@ -0,0 +1,24 @@
+window.Projects = ->
+ $('#project_name').on 'change', ->
+ slug = slugify $(@).val()
+ $('#project_code, #project_path').val slug
+
+ $('.new_project, .edit_project').on 'ajax:before', ->
+ $('.project_new_holder, .project_edit_holder').hide()
+ $('.save-project-loader').show()
+
+ $('form #project_default_branch').chosen()
+ disableButtonIfEmptyField '#project_name', '.project-submit'
+
+$ ->
+ # Git clone panel switcher
+ scope = $ '.project_clone_holder'
+ if scope.length > 0
+ $('a, button', scope).click ->
+ $('a, button', scope).removeClass 'active'
+ $(@).addClass 'active'
+ $('#project_clone', scope).val $(@).data 'clone'
+
+ # Ref switcher
+ $('.project-refs-select').on 'change', ->
+ $(@).parents('form').submit()
diff --git a/app/assets/javascripts/snippets.js b/app/assets/javascripts/snippets.js
deleted file mode 100644
index 11e18eb7..00000000
--- a/app/assets/javascripts/snippets.js
+++ /dev/null
@@ -1,9 +0,0 @@
-$(document).ready(function(){
- $("#snippets-table .snippet").live('click', function(e){
- if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {
- location.href = $(this).attr("url");
- e.stopPropagation();
- return false;
- }
- });
-});
diff --git a/app/assets/javascripts/snippets.js.coffee b/app/assets/javascripts/snippets.js.coffee
new file mode 100644
index 00000000..af4385de
--- /dev/null
+++ b/app/assets/javascripts/snippets.js.coffee
@@ -0,0 +1,6 @@
+$ ->
+ $('#snippets-table .snippet').live 'click', (e) ->
+ if e.target.nodeName isnt 'A' and e.target.nodeName isnt 'INPUT'
+ location.href = $(@).attr 'url'
+ e.stopPropagation()
+ false
diff --git a/app/assets/javascripts/team.js b/app/assets/javascripts/team.js
deleted file mode 100644
index f4b04354..00000000
--- a/app/assets/javascripts/team.js
+++ /dev/null
@@ -1,8 +0,0 @@
-function backToMembers(){
- $("#new_team_member").hide("slide", { direction: "right" }, 150, function(){
- $("#team-table").show("slide", { direction: "left" }, 150, function() {
- $("#new_team_member").remove();
- $(".add_new").show();
- });
- });
-}
diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss
index 3c160358..c5b37916 100644
--- a/app/assets/stylesheets/common.scss
+++ b/app/assets/stylesheets/common.scss
@@ -1,11 +1,9 @@
-.diff_file_header a,
-.file_stats a {
- color:$style_color;
-}
-
-
/** LAYOUT **/
+body {
+ margin-bottom:20px;
+}
+
.container {
padding-top:0;
z-index:5;
@@ -40,30 +38,6 @@
color: $link_color;
}
-.widget {
- @include shade;
- padding:20px;
- margin-bottom:20px;
- border: 1px solid #DDD;
- border-radius: 5px;
- background:#fafafa;
-
- .link_holder {
- background:#eee;
- position:relative;
- left:-20px;
- top:20px;
- padding:10px 20px;
- width:100%;
- border-top:1px solid #ccc;
-
- a {
- font-size:14px;
- color:#666;
- }
- }
-}
-
.help li { color:#111 }
.back_link {
@@ -88,16 +62,6 @@
padding-left:20px;
}
-.number {
- border-radius: 4px;
- text-shadow: none;
- background: rgba(0,0,0,.12);
- text-align: center;
- padding: 2px 4px;
- line-height:18px;
- margin-left:2px;
-}
-
table a code {
position: relative;
top: -2px;
@@ -129,26 +93,18 @@ table a code {
border-bottom:1px solid #ccc;
h4 {
- color:#444;
- font-size:22px;
+ color:#666;
+ font-size:18px;
+ line-height:38px;
padding-top:5px;
margin:2px;
+ font-weight:normal;
}
}
.git_url_wrapper {
margin-right:50px
}
-.file_stats {
- span {
- img {
- width:14px;
- float:left;
- margin-right:6px;
- padding:2px 0;
- }
- }
-}
.handle:hover {
cursor:move;
@@ -172,10 +128,6 @@ span.update-author {
display:block;
}
/** END UPDATE ITEM **/
-.ajax-tab-loading {
- padding:40px;
- display:none;
-}
.dashboard-loader {
float:left;
margin:10px;
@@ -186,15 +138,144 @@ span.update-author {
font-weight:bold;
}
-a.project-update.titled {
- position:relative;
- padding-left:35% !important;
- .title-block {
- padding:10px;
- width:35%;
- position:absolute;
- left:0;
- top:0;
+.neib {
+ margin-right:10px;
+}
+
+.label {
+ background-color: #474D57;
+
+ &.label-tag {
+ background: none;
+ border: none;
+ padding:4px 6px;
+ color:#444;
+ text-shadow:0 0 1px #fff;
+
+ &.grouped {
+ float: left;
+ margin-right: 6px;
+ padding: 6px;
+ }
+ }
+ &.label-issue {
+ background-color: #eee;
+ border: 1px solid #ccc;
+ padding:4px 6px;
+ color:#444;
+ text-shadow:0 0 1px #fff;
+
+ &.grouped {
+ float: left;
+ margin-right: 6px;
+ padding: 6px;
+ }
+ }
+
+ &.label-success {
+ background-color: #8D8;
+ color: #333;
+ text-shadow: 0 1px 1px white;
+ }
+
+ &.label-error {
+ background-color: #D88;
+ color: #333;
+ text-shadow: 0 1px 1px white;
+ }
+}
+
+.event_label {
+ @extend .label;
+ background-color: #999;
+
+ &.pushed {
+ background-color: #4A97BD;
+ }
+
+ &.opened {
+ background-color: #469847;
+ }
+
+ &.closed {
+ background-color: #B94A48;
+ }
+
+ &.merged {
+ background-color: #2A2;
+ }
+
+ &.joined {
+ background-color: #1ca9dd;
+ }
+
+ &.left {
+ background-color: #888;
+ float:none;
+ }
+}
+
+form {
+ @extend .form-horizontal;
+
+ .actions {
+ @extend .form-actions;
+ }
+
+ .clearfix {
+ @extend .control-group;
+ }
+
+ .input {
+ @extend .controls;
+ }
+
+ label {
+ @extend .control-label;
+ }
+ .xlarge {
+ @extend .input-xlarge;
+ }
+ .xxlarge {
+ @extend .input-xxlarge;
+ }
+}
+
+
+.field_with_errors {
+ display:inline;
+}
+
+ul.breadcrumb {
+ background:white;
+ border:none;
+ li {
+ display: inline;
+ text-shadow: 0 1px 0 white
+ }
+
+ a {
+ color:#474D57;
+ font-weight:bold;
+ font-size:14px;
+ }
+
+ .arrow {
+ background: url("images.png") no-repeat -85px -77px;
+ width: 19px;
+ height: 16px;
+ float: left;
+ position: relative;
+ left: -10px;
+ padding:0;
+ margin:0;
+ }
+}
+
+input[type=text] {
+ &.large_text {
+ padding:6px;
+ font-size:16px;
}
}
@@ -270,40 +351,6 @@ p.time {
}
-/**
- * Dashboard page
- *
- */
-.dashboard_category {
- margin-bottom:30px;
- h3 a {
- color:#474D57;
- &:hover {
- text-decoration:underline;
- }
- }
-
- .dashboard_block {
- .dash_project_item {
- margin-bottom:10px;
- border:none;
- padding:0px 5px;
- .project_link {
- color:#888;
- &:hover {
- color:#111;
- .ico.project {
- background-position:-209px -21px;
- }
- }
- }
- h4 {
- color:#666;
- }
- }
- }
-}
-
.styled_image {
border:2px solid #ddd;
}
@@ -393,46 +440,48 @@ p.time {
}
}
-.btn {
- &.very_small {
- font-size:11px;
- padding:2px 6px;
- margin:2px;
+.votes {
+ font-size: 13px;
+ line-height: 15px;
+ .progress {
+ height: 4px;
+ margin: 0;
+ .bar {
+ float: left;
+ height: 100%;
+ }
+ .bar-success {
+ background-color: #468847;
+ @include bg-gradient(#62C462, #51A351);
+ }
+ .bar-danger {
+ background-color: #B94A48;
+ @include bg-gradient(#EE5F5B, #BD362F);
+ }
}
-
- &.grouped {
- margin-right:7px;
- float:left;
+ .upvotes {
+ display: inline-block;
+ color: #468847;
}
-
- &.padded {
- margin-right:3px;
- padding:4px 10px 4px;
+ .downvotes {
+ display: inline-block;
+ color: #B94A48;
}
}
-
-
-.prettyprint {
- background-color: #fefbf3;
- padding: 9px;
- border: 1px solid rgba(0,0,0,.2);
- -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.1);
- -moz-box-shadow: 0 1px 2px rgba(0,0,0,.1);
- box-shadow: 0 1px 2px rgba(0,0,0,.1);
+.votes-block {
+ margin: 14px 6px 6px 0;
+ .downvotes {
+ float: right;
+ }
}
-
-.hint {
- font-style: italic;
- color: #999;
-}
-
-.upvotes {
- font-size: 14px;
- font-weight: bold;
- color: #468847;
- text-align: right;
- padding: 4px;
- margin: 2px;
+.votes-inline {
+ display: inline-block;
+ margin: 0 8px;
+ .progress {
+ display: inline-block;
+ padding: 0 0 2px;
+ width: 45px;
+ }
}
/* Fix for readme code (stopped it from being yellow) */
@@ -549,14 +598,6 @@ li.note {
}
-/**
- * Milestones list
- *
- */
-
-.milestone {
- @extend .wll;
-}
/**
* Admin area
@@ -603,11 +644,10 @@ li.note {
*
*/
.event_lp {
- @extend .alert-info;
+ @extend .ui-box;
+ color:#777;
margin-bottom:20px;
padding:8px;
- border-style: solid;
- border-width: 1px;
@include border-radius(4px);
min-height:22px;
@@ -621,88 +661,19 @@ li.note {
cursor:pointer;
}
-/**
- * Issues, MRs legend
- *
- */
-
-.list_legend {
- float:left;
- margin-right:20px;
- .icon {
- width:12px;
- height:12px;
- float:left;
- margin-right:5px;
- margin-top: 2px;
- @include border-radius(4px);
- &.today{
- background: #ADA;
- border:1px solid #8B8;
- }
- &.closed {
- background: #DDD;
- border:1px solid #BBB;
- }
- &.yours {
- background: #AAD;
- border:1px solid #88B;
- }
- &.merged {
- background: #DAD;
- border:1px solid #B8B;
- }
- }
- .text {
- padding-bottom: 10px;
- float:left;
- }
-}
-
.merge_request,
.issue {
- .list_legend {
- margin-right: 5px;
- margin-top: 14px;
- .icon {
- width:8px;
- height:8px;
- float:left;
- margin-right:5px;
- @include border-radius(4px);
- border:1px solid #ddd;
- }
- }
-
&.today{
background: #EFE;
border-color:#CEC;
- .icon {
- background: #ADA;
- border:1px solid #8B8;
- }
}
&.closed {
background: #F5f5f5;
border-color:#E5E5E5;
- .icon {
- background: #DDD;
- border:1px solid #BBB;
- }
- }
- &.yours {
- .icon {
- background: #AAD;
- border:1px solid #88B;
- }
}
&.merged {
background: #F5f5f5;
border-color:#E5E5E5;
- .icon {
- background: #DAD;
- border:1px solid #B8B;
- }
}
}
@@ -714,7 +685,7 @@ li.note {
margin-right:40px;
.prev {
- @extend .borders;
+ @extend .thumbnail;
height:120px;
width:175px;
margin-bottom:10px;
@@ -743,3 +714,31 @@ li.note {
text-align:center;
margin-bottom:10px;
}
+
+.oauth_select_holder {
+ padding:20px;
+ img {
+ padding:5px;
+ margin-right:10px;
+ }
+ .active {
+ img {
+ border:1px solid #ccc;
+ background:$hover;
+ @include border-radius(5px);
+ }
+ }
+}
+
+.btn-build-token {
+ float: left;
+ padding: 6px 20px;
+ margin-right: 12px;
+}
+
+.gitlab-promo {
+ a {
+ color:#aaa;
+ margin-right: 30px;
+ }
+}
diff --git a/app/assets/stylesheets/gitlab_bootstrap.scss b/app/assets/stylesheets/gitlab_bootstrap.scss
deleted file mode 100644
index 03beeaef..00000000
--- a/app/assets/stylesheets/gitlab_bootstrap.scss
+++ /dev/null
@@ -1,832 +0,0 @@
-body {
- margin-bottom:20px;
-}
-
-pre {
- font-family:'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
-
- &.dark {
- background: #333;
- color:#f5f5f5;
- }
-}
-
-a {
- outline: none;
- color: $link_color;
- &:hover {
- text-decoration:none;
- color: $blue_link;
- }
-
- &.btn {
- color: $style_color;
- }
-
- &.dark {
- color: $style_color;
- }
-
- &.lined {
- text-decoration:underline;
- &:hover { text-decoration:underline; }
- }
-
- &.gray {
- color:gray;
- }
-
- &.supp_diff_link {
- text-align:center;
- padding:20px 0;
- background:#f1f1f1;
- width:100%;
- float:left;
- }
-
- &.neib {
- margin-right:15px;
- }
-}
-
-.neib {
- margin-right:10px;
-}
-
-.alert-message {
- @extend .alert;
-
- &.success {
- @extend .alert-success;
- }
-
- &.error {
- @extend .alert-error;
- }
-}
-
-.alert {
- &.alert-well {
- background:#ddd;
- border:1px solid #ccc;
- background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #ddd), to(#dfdfdf));
- background-image: -webkit-linear-gradient(#ddd 6.6%, #dfdfdf);
- background-image: -moz-linear-gradient(#ddd 6.6%, #dfdfdf);
- background-image: -o-linear-gradient(#ddd 6.6%, #dfdfdf);
- color:#111;
- }
-}
-
-h3, h4, h5, h6 {
- line-height: 36px;
-}
-
-h5 {
- font-size:14px;
-}
-
-
-table {
- width:100%;
- th {
- padding-top: 9px;
- font-weight: bold;
- vertical-align: middle;
- }
- th, td {
- padding: 10px 10px 9px;
- line-height: 18px;
- text-align: left;
- }
-
- &.bordered-table {
- border: 1px solid #DDD;
- border-collapse: separate;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- }
-
- &.zebra-striped {
- @extend .table-striped;
- }
-}
-
-.btn {
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f1f1f1), color-stop(25%, #f1f1f1), to(#e6e6e6));
- background-image: -webkit-linear-gradient(#f1f1f1, #f1f1f1 25%, #e6e6e6);
- background-image: -moz-linear-gradient(top, #f1f1f1, #f1f1f1 25%, #e6e6e6);
- background-image: -ms-linear-gradient(#f1f1f1, #f1f1f1 25%, #e6e6e6);
- background-image: -o-linear-gradient(#f1f1f1, #f1f1f1 25%, #e6e6e6);
- background-image: linear-gradient(#f1f1f1, #f1f1f1 25%, #e6e6e6);
-
- &:hover {
- }
-
- &.btn-primary {
- background:$link_color;
- border-color: #2A79A3;
- &:hover {
- background:$blue_link;
- }
- }
- &.primary {
- @extend .btn-primary;
- }
-
- &.success {
- color: #fff;
- text-shadow: 0 0 1px #111;
- background: #5bb75b;;
- font-weight: bold;
-
- &:hover {
- background-color: #51a351;
- color: #fff;
- }
- }
-
- &.danger,
- &.btn-danger {
- color:#fff;
- background: #DA4E49;
- border-color: #BD362F;
-
- &:hover {
- color:#fff;
- background: #EE4E49;
- }
- }
-
- &.danger {
- @extend .btn-danger;
- }
-
- &.small {
- @extend .btn-small;
- }
-
- &.active {
- border-color:#aaa;
- background-color:#ccc;
- }
-}
-
-a:focus {
- outline: none;
-}
-
-.nav-pills a:hover {
- background-color:#888;
-}
-
-.nav-pills .active a {
- background-color: $style_color;
-}
-
-.label {
- background-color: #474D57;
- &.label-important {
- background-color: #B94A48;
- }
-
- &.label-issue {
- background-color: #eee;
- border: 1px solid #ccc;
- padding:4px 6px;
- color:#444;
- text-shadow:0 0 1px #fff;
-
- &.grouped {
- float: left;
- margin-right: 6px;
- padding: 6px;
- }
- }
-}
-
-.nav-tabs > li > a, .nav-pills > li > a {
- color:$style_color;
-}
-
-.nav-tabs > .active > a {
- font-weight:bold;
-}
-
-/** COLORS **/
-.cgray { color:gray; }
-.cred { color:#D12F19; }
-.cgreen { color:#44aa22; }
-.cblack { color:#111; }
-.cdark { color:#444 }
-.cwhite { color:#fff !important }
-.bgred { background: #F2DEDE !important}
-
-/** COMMON STYLES **/
-.left {
- float:left;
-}
-.right {
- float:right !important;
-}
-.width-50p{
- width:50%;
-}
-.width-49p{
- width:49%;
-}
-.width-30p{
- width:30%;
-}
-.width-65p{
- width:65%;
-}
-.width-100p{
- width:100%;
-}
-.append-bottom-10 {
- margin-bottom:10px;
-}
-.append-bottom-20 {
- margin-bottom:20px;
-}
-.prepend-top-10 {
- margin-top:10px;
-}
-
-.prepend-top-20 {
- margin-top:20px;
-}
-
-.padded {
- padding:20px;
-}
-
-.ipadded {
- padding:20px !important;
-}
-.lborder {
- border-left:1px solid #eee;
-}
-
-.borders {
- border: 1px solid #ccc;
- @include shade;
-}
-.no-borders {
- border:none;
-}
-table.no-borders {
- border:none;
- tr, td { border:none }
-}
-.no-padding {
- padding:0 !important;
-}
-.underlined {
- border-bottom: 1px solid $border_color;
-}
-.vlink {
- color: $link_color !important;
-}
-
-.pretty_label {
- @include round-borders-all(4px);
- padding:2px 4px;
- background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8));
- background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8);
- background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8);
- background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8);
- color: #777;
- border: 1px solid #DEDFE1;
-
- &.branch {
- border:none;
- font-size:13px;
- background: #474D57;
- color:#fff;
- font-weight:bold;
- font-family: monospace;
- }
-}
-
-.event_label {
- @extend .label;
- background-color: #999;
-
- &.pushed {
- background-color: #3A87AD;
- }
-
- &.opened {
- background-color: #468847;
- }
-
- &.closed {
- background-color: #B94A48;
- }
-
- &.merged {
- background-color: #2A2;
- }
-}
-
-img.avatar {
- float:left;
- margin-right:15px;
- width:40px;
- border:1px solid #ddd;
- padding:1px;
-
- &.s16 {
- width:16px;
- height:16px;
- }
- &.s24 {
- width:24px;
- height:24px;
- }
- &.s32 {
- width:32px;
- height:32px;
- }
-}
-
-img.lil_av {
- padding-left: 4px;
- padding-right:3px;
-}
-
-form {
- @extend .form-horizontal;
-
- .actions {
- @extend .form-actions;
- }
-
- .clearfix {
- @extend .control-group;
- }
-
- .input {
- @extend .controls;
- }
-
- label {
- @extend .control-label;
- }
- .xlarge {
- @extend .input-xlarge;
- }
- .xxlarge {
- @extend .input-xxlarge;
- }
-}
-
-/**
- * List li block element #1
- *
- */
-.wll {
- background-color: #FFF;
- padding: 10px 5px;
- min-height: 20px;
- border-bottom: 1px solid #eee;
- border-bottom: 1px solid rgba(0, 0, 0, 0.05);
- &.smoke {
- background-color:#f5f5f5;
- }
- &:hover {
- background:$hover;
- }
- &:last-child { border:none }
- p { padding-top:5px; margin:0; color:$style_color;}
- .author { color: #999; }
- p {
- color:#222;
- margin-bottom: 0;
- img {
- position:relative;
- top:3px;
- }
- }
-}
-
-
-/**
- * Block element #2
- *
- */
-.entry {
- position: relative;
- padding: 7px 15px;
- margin-bottom: 18px;
- color: #404040;
- filter:none;
-
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
- text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
-
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
-
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
-
- background:#F1F1F1;
- border: 1px solid #ccc;
-
-
- p {
- color:$style_color;
- margin-bottom: 0;
- img {
- position:relative;
- top:3px;
- }
- }
-}
-
-
-/**
- * Big UI Block for show page content
- *
- */
-.ui-box {
- background:#F9F9F9;
- margin-bottom: 25px;
- @include round-borders-all(4px);
- border-color: #CCC;
- @include solid_shade;
-
- ul {
- margin:0;
- }
-
- h5, .title {
- padding: 0 10px;
- @include round-borders-top(4px);
- border-bottom: 1px solid #bbb;
- background:#eee;
- background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
- background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
-
- &.small {
- line-height: 28px;
- font-size: 14px;
- line-height:28px;
- text-shadow: 0 1px 1px white;
- }
-
- form {
- padding:9px 0;
- margin:0px;
- }
-
- .nav-pills {
- li {
- padding:3px 0;
- &.active a { background-color:$style_color; }
- a {
- border-radius:7px;
- }
- }
- }
- }
-
- .bottom {
- background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
- background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
- @include round-borders-bottom(4px);
- border-bottom:none;
- border-top: 1px solid #bbb;
- }
-
- &.padded {
- h5, .title {
- margin: -20px;
- margin-bottom: 0;
- padding: 5px 20px;
- }
- .middle_title {
- background:#f5f5f5;
- margin:20px -20px;
- padding: 0 20px;
- border-top:1px solid #eee;
- border-bottom:1px solid #eee;
- font-size:14px;
- color:#777;
- }
- }
- .row_title {
- font-weight:bold;
- color:#444;
- &:hover {
- color:#444;
- text-decoration:underline;
- }
- }
-
- li, .wll {
- padding:10px;
- &:first-child {
- @include round-borders-top(4px);
- border-top:none;
- }
-
- &:last-child {
- @include round-borders-bottom(4px);
- border:none;
- }
- }
-
-}
-
-table.admin-table {
- @extend .table-bordered;
- @extend .zebra-striped;
- @include solid_shade;
- th {
- border-color: #CCC;
- border-bottom: 1px solid #bbb;
- background:#eee;
- background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
- background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
- }
-}
-
-.field_with_errors {
- display:inline;
-}
-
-ul.breadcrumb {
- background:white;
- border:none;
- li {
- display: inline;
- text-shadow: 0 1px 0 white
- }
-
- a {
- color:#474D57;
- font-weight:bold;
- font-size:14px;
- }
-
- .arrow {
- background: url("images.png") no-repeat -85px -77px;
- width: 19px;
- height: 16px;
- float: left;
- position: relative;
- left: -10px;
- padding:0;
- margin:0;
- }
-}
-
-.nothing_here_message {
- text-align:center;
- padding:20px;
- color:#777;
-}
-
-/**
- * UI box element
- * contains top, middle, bottom blocks
- *
- */
-.main_box {
- @extend .borders;
- @extend .prepend-top-20;
- @extend .append-bottom-20;
- border-width:1px;
- @include solid_shade;
-
-
- img { max-width: 100%; }
-
- pre {
- code {
- background: none !important;
- }
- }
-
- .top_box_content,
- .middle_box_content,
- .bottom_box_content {
- padding:15px;
-
- pre {
- background: none !important;
- margin:0;
- border:none;
- padding:0;
- }
- }
-
- .middle_box_content {
- border-radius:0;
- border:none;
- font-size:12px;
- background-color:#f5f5f5;
- border:none;
- border-top:1px solid #eee;
- }
-
- .bottom_box_content {
- border-top:1px solid #eee;
- }
-}
-
-input[type=text] {
- &.large_text {
- padding:6px;
- font-size:16px;
- }
-}
-
-p {
- &.slead {
- color:#456;
- font-size:16px;
- margin-bottom: 12px;
- font-weight: 200;
- line-height: 24px;
- }
-}
-
-h3.page_title {
- color:#456;
- font-size:20px;
- font-weight: normal;
- line-height: 28px;
-}
-
-/**
- * File content holder
- *
- */
-.file_holder {
- border:1px solid #CCC;
- margin-bottom:1em;
- @include solid_shade;
-
- .file_title {
- border-bottom: 1px solid #bbb;
- background:#eee;
- background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
- background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
- margin: 0;
- font-weight: normal;
- font-weight: bold;
- text-align: left;
- color: #666;
- padding: 9px 10px;
- height:18px;
-
- .options {
- float:right;
- margin-top: -5px;
- }
-
- .file_name {
- color:$style_color;
- font-size:14px;
- text-shadow: 0 1px 1px #fff;
- small {
- color:#999;
- font-size:13px;
- }
- }
- }
- .file_content {
- background:#fff;
- font-size: 11px;
-
- &.wiki {
- font-size: 13px;
- code {
- padding:0 4px;
- }
- padding:20px;
- h1, h2 {
- line-height: 46px;
- }
- h3, h4 {
- line-height: 40px;
- }
- }
-
- &.image_file {
- background:#eee;
- text-align:center;
- img {
- padding:100px;
- max-width:300px;
- }
- }
-
- &.blob_file {
-
- }
-
- /**
- * Blame file
- */
- &.blame {
- tr {
- border-bottom: 1px solid #eee;
- }
- td {
- padding:5px;
- }
- .author,
- .blame_commit {
- background:#f5f5f5;
- vertical-align:top;
- }
- .lines {
- pre {
- padding:0;
- margin:0;
- background:none;
- border:none;
- }
- }
- }
-
- &.logs {
- background:#eee;
- max-height: 700px;
- overflow-y: auto;
-
- ol {
- margin-left:40px;
- padding: 10px 0;
- border-left: 1px solid #CCC;
- margin-bottom:0;
- background: white;
- li {
- color:#888;
- p {
- margin:0;
- color:#333;
- line-height:24px;
- padding-left: 10px;
- }
-
- &:hover {
- background:$hover;
- }
- }
- }
- }
-
- /**
- * Code file
- */
- &.code {
- padding:0;
- td.code {
- width: 100%;
- .highlight {
- margin-left: 55px;
- overflow:auto;
- overflow-y:hidden;
- }
- }
- .highlight pre {
- white-space: pre;
- word-wrap:normal;
- }
-
- table.highlighttable {
- border: none;
- }
- body.project-page table.highlighttable td { border: none }
- table.highlighttable tr:hover { background:none;}
-
- table.highlighttable pre{
- line-height:16px !important;
- font-size:12px !important;
- }
-
- table.highlighttable .linenodiv pre {
- text-align: right;
- padding-right: 4px;
- color:#666;
- }
- }
- }
-}
diff --git a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss
new file mode 100644
index 00000000..ae66bd20
--- /dev/null
+++ b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss
@@ -0,0 +1,153 @@
+/**
+ * ===================================
+ * Contain 3 main UI block elements:
+ * .main_box - for show pages
+ * .ui-box - for simple block & widgets
+ * ===================================
+ */
+
+/**
+ * UI box element
+ * contains top, middle, bottom blocks
+ *
+ */
+.main_box {
+ @extend .borders;
+ @extend .prepend-top-20;
+ @extend .append-bottom-20;
+ border-width:1px;
+ @include solid_shade;
+
+
+ img { max-width: 100%; }
+
+ pre {
+ code {
+ background: none !important;
+ }
+ }
+
+ .top_box_content,
+ .middle_box_content,
+ .bottom_box_content {
+ padding:15px;
+
+ pre {
+ background: none !important;
+ margin:0;
+ border:none;
+ padding:0;
+ }
+ }
+
+ .middle_box_content {
+ border-radius:0;
+ border:none;
+ font-size:12px;
+ background-color:#f5f5f5;
+ border:none;
+ border-top:1px solid #eee;
+ }
+
+ .bottom_box_content {
+ border-top:1px solid #eee;
+ }
+}
+
+/**
+ * Big UI Block for show page content
+ *
+ */
+.ui-box {
+ background:#F9F9F9;
+ margin-bottom: 25px;
+ @include round-borders-all(4px);
+ border-color: #CCC;
+ @include solid_shade;
+
+ &.white {
+ background:#fff;
+ }
+
+ ul {
+ margin:0;
+ }
+
+ h5, .title {
+ padding: 0 10px;
+ @include round-borders-top(4px);
+ @include bg-gray-gradient;
+ border-bottom: 1px solid #bbb;
+
+ &.small {
+ line-height: 28px;
+ font-size: 14px;
+ line-height:28px;
+ text-shadow: 0 1px 1px white;
+ }
+
+ form {
+ padding:9px 0;
+ margin:0px;
+ }
+
+ .nav-pills {
+ li {
+ padding:3px 0;
+ &.active a { background-color:$style_color; }
+ a {
+ border-radius:7px;
+ }
+ }
+ }
+ }
+
+ .bottom {
+ @include bg-gray-gradient;
+ @include round-borders-bottom(4px);
+ border-bottom:none;
+ border-top: 1px solid #bbb;
+ }
+
+ &.padded {
+ h5, .title {
+ margin: -20px;
+ margin-bottom: 0;
+ padding: 5px 20px;
+ }
+ .middle_title {
+ background:#f5f5f5;
+ margin:20px -20px;
+ padding: 0 20px;
+ border-top:1px solid #eee;
+ border-bottom:1px solid #eee;
+ font-size:14px;
+ color:#777;
+ }
+ }
+ .row_title {
+ font-weight:bold;
+ color:#444;
+ &:hover {
+ color:#444;
+ text-decoration:underline;
+ }
+ }
+
+ li, .wll {
+ padding:10px;
+ &:first-child {
+ @include round-borders-top(4px);
+ border-top:none;
+ }
+
+ &:last-child {
+ @include round-borders-bottom(4px);
+ border:none;
+ }
+ }
+
+ .ui-box-body {
+ padding:10px;
+ }
+}
diff --git a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss
new file mode 100644
index 00000000..380fc3e3
--- /dev/null
+++ b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss
@@ -0,0 +1,93 @@
+.btn {
+ @include bg-gradient(#f7f7f7, #d5d5d5);
+ border-color:#aaa;
+ &:hover {
+ @include bg-gray-gradient;
+ border-color:#bbb;
+ color:#333;
+ }
+
+ &.primary {
+ background:#2a79A3;
+ @include bg-gradient(#47A7b7, #2585b5);
+ border-color: #2A79A3;
+ color:#fff;
+ text-shadow: 0 1px 1px #268;
+ &:hover {
+ background:$blue_link;
+ color:#fff;
+ }
+
+ &.disabled {
+ color:#fff;
+ background:#29B;
+ }
+ }
+
+ &.success {
+ @extend .btn-success;
+
+ &:hover {
+ @extend .btn-success;
+ background: #51a351;
+ }
+
+ &.disabled {
+ color:#fff;
+ background:#2b2;
+ }
+ }
+
+ &.save-btn {
+ @extend .wide;
+ @extend .primary;
+ }
+
+ &.cancel-btn {
+ float:right;
+ }
+
+ &.wide {
+ padding-left:30px;
+ padding-right:30px;
+ }
+
+ &.danger {
+ @extend .btn-danger;
+ border-color: #BD362F;
+
+ &:hover {
+ color:#fff;
+ background: #EE4E49;
+ }
+ }
+
+ &.danger {
+ @extend .btn-danger;
+ }
+
+ &.small {
+ @extend .btn-small;
+ }
+
+ &.active {
+ border-color:#aaa;
+ background-color:#ccc;
+ }
+
+ &.very_small {
+ font-size:11px;
+ padding:2px 6px;
+ margin:2px;
+ }
+
+ &.grouped {
+ margin-right:7px;
+ float:left;
+ }
+
+ &.padded {
+ margin-right:3px;
+ padding:4px 10px 4px;
+ }
+}
diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss
new file mode 100644
index 00000000..b9459ee6
--- /dev/null
+++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss
@@ -0,0 +1,84 @@
+/** COLORS **/
+.cgray { color:gray }
+.cred { color:#D12F19 }
+.cgreen { color:#4a2 }
+.cblack { color:#111 }
+.cdark { color:#444 }
+.cwhite { color:#fff!important }
+.bgred { background:#F2DEDE!important }
+
+/** COMMON CLASSES **/
+.left { float:left }
+.right { float:right!important }
+.width-50p { width:50% }
+.width-49p { width:49% }
+.width-30p { width:30% }
+.width-65p { width:65% }
+.width-100p { width:100% }
+.append-bottom-10 { margin-bottom:10px }
+.append-bottom-20 { margin-bottom:20px }
+.prepend-top-10 { margin-top:10px }
+.prepend-top-20 { margin-top:20px }
+.padded { padding:20px }
+.ipadded { padding:20px!important }
+.lborder { border-left:1px solid #eee }
+.no-padding { padding:0 !important; }
+.underlined { border-bottom: 1px solid #CCC; }
+.no-borders { border:none; }
+.vlink { color: $link_color !important; }
+.borders { border: 1px solid #ccc; @include shade; }
+.hint { font-style: italic; color: #999; }
+
+/** PILLS & TABS**/
+.nav-pills a:hover { background-color:#888; }
+.nav-pills .active a { background-color: $style_color; }
+.nav-tabs > li > a, .nav-pills > li > a { color:$style_color; }
+.nav.nav-tabs {
+ li {
+ > a {
+ padding:8px 20px;
+ margin-right: 7px;
+ border-color: #EEE;
+ color:#888;
+ border-bottom: 1px solid #ddd;
+ .badge {
+ background-color: #eee;
+ color:#888;
+ text-shadow:0 1px 1px #fff;
+ }
+ }
+ &.active {
+ > a {
+ border-color: #CCC;
+ border-bottom: 1px solid #fff;
+ color:#333;
+ }
+ }
+ }
+}
+
+/** ALERT MESSAGES **/
+.alert-message { @extend .alert; }
+.alert-messag.success { @extend .alert-success; }
+.alert-message.error { @extend .alert-error; }
+
+/** AVATARS **/
+img.avatar { float:left; margin-right:15px; width:40px; border:1px solid #ddd; padding:1px; }
+img.avatar.s16 { width:16px; height:16px; }
+img.avatar.s24 { width:24px; height:24px; }
+img.avatar.s32 { width:32px; height:32px; }
+img.lil_av { padding-left: 4px; padding-right:3px; }
+
+/** HELPERS **/
+.nothing_here_message { text-align:center; padding:20px; color:#777; }
+p.slead { color:#456; font-size:16px; margin-bottom: 12px; font-weight: 200; line-height: 24px; }
+
+/** FORMS **/
+input[type='search'].search-text-input {
+ background-image: url("icon-search.png");
+ background-repeat: no-repeat;
+ background-position: 10px;
+ padding-left:25px;
+ @include border-radius(4px);
+ border:1px solid #ccc;
+}
diff --git a/app/assets/stylesheets/gitlab_bootstrap/files.scss b/app/assets/stylesheets/gitlab_bootstrap/files.scss
new file mode 100644
index 00000000..d39fdb27
--- /dev/null
+++ b/app/assets/stylesheets/gitlab_bootstrap/files.scss
@@ -0,0 +1,156 @@
+/**
+ * File content holder
+ *
+ */
+.file_holder {
+ border:1px solid #BBB;
+ margin-bottom:1em;
+ @include solid_shade;
+
+ .file_title {
+ border-bottom: 1px solid #bbb;
+ @include bg-dark-gray-gradient;
+ margin: 0;
+ font-weight: normal;
+ font-weight: bold;
+ text-align: left;
+ color: #666;
+ padding: 9px 10px;
+ height:18px;
+
+ .options {
+ float:right;
+ margin-top: -5px;
+ }
+
+ .file_name {
+ color:$style_color;
+ font-size:14px;
+ text-shadow: 0 1px 1px #fff;
+ small {
+ color:#999;
+ font-size:13px;
+ }
+ }
+ }
+ .file_content {
+ background:#fff;
+ font-size: 11px;
+
+ &.wiki {
+ font-size: 13px;
+ code {
+ padding:0 4px;
+ }
+ padding:20px;
+ h1, h2 {
+ line-height: 46px;
+ }
+ h3, h4 {
+ line-height: 40px;
+ }
+ }
+
+ &.image_file {
+ background:#eee;
+ text-align:center;
+ img {
+ padding:100px;
+ max-width:300px;
+ }
+ }
+
+ &.blob_file {
+
+ }
+
+ /**
+ * Blame file
+ */
+ &.blame {
+ tr {
+ border-bottom: 1px solid #eee;
+ }
+ td {
+ padding:5px;
+ }
+ .author,
+ .blame_commit {
+ background:#f5f5f5;
+ vertical-align:top;
+ }
+ .lines {
+ pre {
+ padding:0;
+ margin:0;
+ background:none;
+ border:none;
+ }
+ }
+ }
+
+ &.logs {
+ background:#eee;
+ max-height: 700px;
+ overflow-y: auto;
+
+ ol {
+ margin-left:40px;
+ padding: 10px 0;
+ border-left: 1px solid #CCC;
+ margin-bottom:0;
+ background: white;
+ li {
+ color:#888;
+ p {
+ margin:0;
+ color:#333;
+ line-height:24px;
+ padding-left: 10px;
+ }
+
+ &:hover {
+ background:$hover;
+ }
+ }
+ }
+ }
+
+ /**
+ * Code file
+ */
+ &.code {
+ padding:0;
+ td.code {
+ width: 100%;
+ .highlight {
+ margin-left: 55px;
+ overflow:auto;
+ overflow-y:hidden;
+ }
+ }
+ .highlight pre {
+ white-space: pre;
+ word-wrap:normal;
+ }
+
+ table.highlighttable {
+ border: none;
+ }
+ body.project-page table.highlighttable td { border: none }
+ table.highlighttable tr:hover { background:none;}
+
+ table.highlighttable pre{
+ line-height:16px !important;
+ font-size:12px !important;
+ }
+
+ table.highlighttable .linenodiv pre {
+ text-align: right;
+ padding-right: 4px;
+ color:#666;
+ }
+ }
+ }
+}
+
diff --git a/app/assets/stylesheets/gitlab_bootstrap/lists.scss b/app/assets/stylesheets/gitlab_bootstrap/lists.scss
new file mode 100644
index 00000000..402ba04b
--- /dev/null
+++ b/app/assets/stylesheets/gitlab_bootstrap/lists.scss
@@ -0,0 +1,30 @@
+/** LISTS **/
+
+ul {
+ /**
+ * List li block element #1
+ *
+ */
+ .wll {
+ background-color: #FFF;
+ padding: 10px 5px;
+ min-height: 20px;
+ border-bottom: 1px solid #eee;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+
+ &.smoke { background-color:#f5f5f5; }
+ &:hover { background:$hover; }
+ &:last-child { border:none }
+ .author { color: #999; }
+
+ p {
+ padding-top:5px;
+ margin:0;
+ color:#222;
+ img {
+ position:relative;
+ top:3px;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/gitlab_bootstrap/tables.scss b/app/assets/stylesheets/gitlab_bootstrap/tables.scss
new file mode 100644
index 00000000..29293867
--- /dev/null
+++ b/app/assets/stylesheets/gitlab_bootstrap/tables.scss
@@ -0,0 +1,45 @@
+table {
+ @extend .table;
+ @extend .table-striped;
+ @include solid_shade;
+ border:1px solid #bbb;
+ width:100%;
+
+ th {
+ font-weight: bold;
+ vertical-align: middle;
+ border-bottom: 1px solid #bbb;
+ text-shadow: 0 1px 1px #fff;
+ @include bg-dark-gray-gradient;
+ }
+
+ th, td {
+ padding: 8px;
+ line-height: 18px;
+ text-align: left;
+ }
+
+ td {
+ border-color:#f1f1f1;
+ &:first-child {
+ border-left:1px solid #bbb;
+ }
+
+ &:last-child {
+ border-right:1px solid #bbb;
+ }
+ }
+
+ &.bordered {
+ @extend .table-bordered;
+ }
+
+ &.lite {
+ border:none;
+ box-shadow:none;
+ tr, td {
+ border:none;
+ background:none !important;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/gitlab_bootstrap/typography.scss b/app/assets/stylesheets/gitlab_bootstrap/typography.scss
new file mode 100644
index 00000000..97e85492
--- /dev/null
+++ b/app/assets/stylesheets/gitlab_bootstrap/typography.scss
@@ -0,0 +1,71 @@
+/**
+ * Headers
+ *
+ */
+h3, h4, h5, h6 { line-height: 36px; }
+h5 { font-size:14px; }
+h3.page_title {
+ color:#456;
+ font-size:20px;
+ font-weight: normal;
+ line-height: 28px;
+}
+
+/** CODE **/
+pre {
+ font-family:'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
+
+ &.dark {
+ background: #333;
+ color:#f5f5f5;
+ }
+}
+
+/**
+ * Links
+ *
+ */
+a {
+ outline: none;
+ color: $link_color;
+ &:hover {
+ text-decoration:none;
+ color: $blue_link;
+ }
+
+ &.btn {
+ color: $style_color;
+ &:hover {
+ color: $style_color;
+ }
+ }
+
+ &.dark {
+ color: $style_color;
+ }
+
+ &.lined {
+ text-decoration:underline;
+ &:hover { text-decoration:underline; }
+ }
+
+ &.gray {
+ color:gray;
+ }
+
+ &.supp_diff_link {
+ text-align:center;
+ padding:20px 0;
+ background:#f1f1f1;
+ width:100%;
+ float:left;
+ }
+
+ &.neib {
+ margin-right:15px;
+ }
+}
+
+a:focus {
+ outline: none;
+}
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index a08f05bd..9b003b8a 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -1,12 +1,21 @@
-table.highlighttable
-{
+table.highlighttable {
margin:0px;
padding:0px;
font-size:12px;
table-layout:fixed;
background: #EEE;
+ box-shadow: none;
+ border: none;
+ td.linenos {
+ background:#eee;
+ border-left:none;
+ }
+ td.code {
+ border-right:none;
+ }
}
+
td.code,
td.linenos{
padding:0;
diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss
index ad8be0bc..75001d3a 100644
--- a/app/assets/stylesheets/main.scss
+++ b/app/assets/stylesheets/main.scss
@@ -1,30 +1,14 @@
@import "bootstrap";
@import "bootstrap-responsive";
-/** GITLAB colors **/
-$text_color:#222;
-$lite_text_color: #666;
-$link_color:#2A79A3;
-$active_link_color:#2FA0BB;
-$active_bg_color:#79C3E0;
-$active_bd_color: #2FA0BB;
-$border_color:#CCC;
-$lite_border_color:#EEE;
-$min_app_width:980px;
-$max_app_width:980px;
-$app_padding:20px;
-$bg_color: #FFF;
-$styled_border_color: #2FA0BB;
-$color: "#4BB8D2";
+/** GitLab colors **/
+$link_color:#3A89A3;
$blue_link: #2fa0bb;
+$style_color: #474d57;
+$hover: #fdf5d9;
-
-/** Style colors **/
-$style_color: #474D57;
-$hover: #FDF5D9;
-
-/** GITLAB Fonts **/
-@font-face { font-family: Korolev; src: url('korolev-medium-compressed.otf'); }
+/** GitLab Fonts **/
+@font-face { font-family: Korolev; src: url('korolev-medium-compressed.otf'); }
/** MIXINS **/
@mixin shade {
@@ -72,7 +56,27 @@ $hover: #FDF5D9;
border-radius: $radius;
}
+@mixin bg-gradient($from, $to) {
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from($from), to($to));
+ background-image: -webkit-linear-gradient($from, $to);
+ background-image: -moz-linear-gradient($from, $to);
+ background-image: -o-linear-gradient($from, $to);
+}
+@mixin bg-gray-gradient {
+ background:#eee;
+ background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
+ background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
+ background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
+ background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
+}
+
+@mixin bg-dark-gray-gradient {
+ background:#eee;
+ background-image: -webkit-linear-gradient(#e9e9e9, #d7d7d7);
+ background-image: -moz-linear-gradient(#e9e9e9, #d7d7d7);
+ background-image: -o-linear-gradient(#e9e9e9, #d7d7d7);
+}
/**
* Header of application.
@@ -109,11 +113,17 @@ $hover: #FDF5D9;
@import "themes/ui_modern.scss";
/**
- * Gitlab bootstrap.
+ * GitLab bootstrap.
* Overrides some styles of twitter bootstrap.
- * Also give some common classes for gitlab app
+ * Also give some common classes for GitLab app
*/
-@import "gitlab_bootstrap.scss";
+@import "gitlab_bootstrap/common.scss";
+@import "gitlab_bootstrap/typography.scss";
+@import "gitlab_bootstrap/buttons.scss";
+@import "gitlab_bootstrap/blocks.scss";
+@import "gitlab_bootstrap/files.scss";
+@import "gitlab_bootstrap/tables.scss";
+@import "gitlab_bootstrap/lists.scss";
/**
@@ -125,7 +135,6 @@ $hover: #FDF5D9;
*/
@import "common.scss";
-
/**
* Styles related to specific part of app
*/
@@ -151,6 +160,11 @@ $hover: #FDF5D9;
*/
@import "sections/notes.scss";
+/**
+ * This file represent profile styles
+ */
+@import "sections/profile.scss";
+
/**
* Devise styles
*/
diff --git a/app/assets/stylesheets/projects.css.scss b/app/assets/stylesheets/projects.css.scss
deleted file mode 100644
index 4bdf5dee..00000000
--- a/app/assets/stylesheets/projects.css.scss
+++ /dev/null
@@ -1,385 +0,0 @@
-.git_url_wrapper { margin-right:50px }
-
-.sidebar aside a{
- display: block;
- position: relative;
- padding: 15px 10px;
- margin: 10px 0 0 0;
-
- font-size:13px;
- font-weight:bold;
- color:#333;
-
- &.current {
- color: white;
- background: $active_bg_color;
- border: 1px solid $active_bd_color;
- border-radius:5px;
-
- -webkit-border-top-right-radius: 0;
- -webkit-border-bottom-right-radius: 0;
- -moz-border-radius-topright: 0px;
- -moz-border-radius-bottomright: 0px;
- border-top-right-radius: 0;
- border-bottom-right-radius: 0;
- margin-right: -1px;
- }
-}
-
-body table .commit a{color: #{$blue_link}}
-body table th, body table td{ border-bottom: 1px solid #DEE2E3;}
-body .fixed{position: fixed; }
-
-/** File stat **/
-.file_stats {
- span {
- img {
- width:14px;
- float:left;
- margin-right: 6px;
- padding:2px 0;
- }
- }
-}
-
-.round-borders {
- @include round-borders-all(4px);
- padding: 4px 0px;
-}
-
-table.round-borders {
- float:left;
- text-align: left;
-}
-
-
-
-/** PROJECTS **/
-input.ssh_project_url {
- padding:5px;
- margin:0px;
- float:right;
- width:400px;
- text-align:center;
-}
-
-#projects-list .project {
- height:50px;
-}
-
-#tree-slider .tree-item,
-#projects-list .project,
-#snippets-table .snippet,
-#issues-table .issue{
- cursor:pointer;
-}
-
-.clear {
- clear: both;
-}
-
-
-
-#user_projects_limit{
- width: 60px;
-}
-
-.handle:hover{
- cursor: move;
-}
-
-.project-refs-form {
- span {
- background: none !important;
- position:static !important;
- width:auto !important;
- height: auto !important;
- }
-}
-
-.project-refs-select {
- width:200px;
-}
-
-.filter .left { margin-right:15px; }
-
-body table .commit {
- a.tree-commit-link {
- color:#444;
- &:hover {
- text-decoration:underline;
- }
- }
-}
-
-/** NEW PROJECT **/
-.new-project-hodler {
- .icon span { background-position: -31px -70px; }
- td { border-bottom: 1px solid #DEE2E3; }
-}
-
-/** Feed entry **/
-.commit,
-.snippet,
-.message {
- .title {
- color:#666;
- a { color:#666 !important; }
- p { margin-top:0px; }
- }
- .author { color: #999 }
-}
-
-/** JQuery UI **/
-.ui-autocomplete { @include round-borders-all(5px); }
-.ui-menu-item { cursor: pointer }
-.ui-selectmenu{
- @include round-borders-all(4px);
- margin-right:10px;
- font-size:1.5em;
- height:auto;
- font-weight:bold;
- .ui-selectmenu-status {
- padding:3px 10px;
- }
-}
-
-#holder {
- background:#FAFAFA;
- border: 1px solid #EEE;
- cursor: move;
- height: 70%;
- overflow: hidden;
-}
-
-/* Project Dashboard Page */
-html, body { height: 100%; }
-
-.news-feed h2{float: left;}
-.news-feed .project-updates {margin-bottom: 20px; display: block; width: 100%;}
-.news-feed .project-updates .data{ padding: 0}
-.news-feed .project-updates a.project-update {padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;}
-.news-feed .project-updates a.project-update:last-child{border-bottom: 0}
-.news-feed .project-updates a.project-update img{float: left; margin-right: 10px;}
-.news-feed .project-updates a.project-update span.update-title, .dashboard-page .news-feed .project-updates li a span.update-author{display: block;}
-.news-feed .project-updates a.project-update span.update-title{margin-bottom: 10px}
-.news-feed .project-updates a.project-update span.update-author{color: #999; font-weight: normal; font-style: italic;}
-.news-feed .project-updates a.project-update span.update-author strong{font-weight: bold; font-style: normal;}
-/* eo Dashboard Page */
-
-
-/** Update entry **/
-.update-data { padding: 0 }
-.update-data { width:100%; }
-.update-data.ui-box .data { padding:0; }
-a.update-item {padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;}
-a.update-item:last-child{border-bottom: 0}
-a.update-item img{float: left; margin-right: 10px;}
-a.update-item span.update-title, .dashboard-page .news-feed .project-updates li a span.update-author{display: block;}
-a.update-item span.update-title{margin-bottom: 10px}
-a.update-item span.update-author{color: #999; font-weight: normal; font-style: italic;}
-a.update-item span.update-author strong{font-weight: bold; font-style: normal;}
-
-
-body .team_member_new .span-6, .team_member_edit .span-6{ padding:10px 0; }
-
-body.projects-page input.text.git-url.project_list_url { width:165px; }
-
-
-body table.no-borders th {
- background:none;
- border-bottom:1px solid #CCC;
- color:#333;
-}
-
-body table.no-borders tr,
-body table.no-borders td{
- border:none;
-}
-
-.ajax-tab-loading {
- padding:40px;
- display:none;
-}
-
-#tree-content-holder { float:left; width:100%; }
-
-#tree-readme-holder {
- float:left;
- width:100%;
-
- .readme {
- @include round-borders-all(4px);
- padding: 4px 15px;
- background:#F7F7F7;
- }
-}
-
-
-
-/* Commit Page */
-.entity-info {float: right;}
-.entity-button{
- background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.192, #fff), to(#f4f4f4));
- background-image: -webkit-linear-gradient(#fff 19.2%, #f4f4f4);
- background-image: -moz-linear-gradient(#fff 19.2%, #f4f4f4);
- background-image: -o-linear-gradient(#fff 19.2%, #f4f4f4);
- box-shadow: 0 -1px 0 white inset;
- display: block;
- border: 1px solid #eee;
- border-radius: 5px;
- margin-bottom: 2px;
- position: relative;
- padding: 4px 10px;
- font-size: 11px;
- padding-right: 20px;
-}
-
-.entity-button i{
- background: url('images.png') no-repeat -138px -27px;
- width: 6px;
- height: 9px;
- float: right;
- position: absolute;
- top: 6px;
- right: 5px;
-}
-.box-arrow{float: right; background: #E3E5EA; padding: 10px; border-radius: 5px; margin-top: 2px; text-shadow: none; color: #999; margin: 1.5em 0;}
-
-h4.dash-tabs {
- margin: 0;
- border-bottom: 1px solid #ccc;
- padding: 10px 10px;
- font-size: 11px;
- padding-left:20px;
- font-weight: bold; text-transform: uppercase;
- background: #F7F7F7;
- margin-bottom:20px;
- height:13px;
-
-}
-
-.dash-button {
- border-right: 1px solid #ddd;
- background:none;
- padding: 10px 15px;
- float:left;
- position:relative;
- top:-10px;
- left:0px;
- height:13px;
-
- &:first-child {
- border-left: 1px solid #ddd;
- }
- &.active {
- background: #eaeaea;
- }
-}
-
-
-.dashboard-loader {
- float:right;
- margin-right:30px;
- display:none;
-}
-
-
-.merge-tabs {
- margin: 0;
- border: 1px solid #ccc;
- padding: 5px;
- font-size: 12px;
- background: #F7F7F7;
- margin-bottom:20px;
- height:26px;
-
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- border-radius: 4px;
-
- .tab {
- font-weight: bold;
- border-right: 1px solid #ddd;
- background:none;
- padding: 10px;
- min-width:60px;
- float:left;
- position:relative;
- top:-5px;
- left:-5px;
- height:16px;
- padding-left:34px;
-
- span {
- width: 20px;
- height: 20px;
- display: inline-block;
- position: absolute;
- left: 8px;
- top: 8px;
- }
-
- &.active {
- background: #eaeaea;
- }
- }
-}
-.merge-tabs.repository .tab span{ background: url("images.png") no-repeat -38px -77px; }
-.activities-tab span { background: url("images.png") no-repeat -161px -1px; }
-.stat-tab span,
-.team-tab span,
-.snippets-tab span { background: url("images.png") no-repeat -38px -77px; }
-.files-tab span { background: url("images.png") no-repeat -112px -23px; }
-
-.merge-notes-tab span { background: url("images.png") no-repeat -161px -1px; }
-.merge-commits-tab span { background: url("images.png") no-repeat -86px 1px; }
-.merge-diffs-tab span { background: url("images.png") no-repeat -118px 1px; }
-.merge-tabs .dashboard-loader { padding:8px; }
-
-.user-mention {
- color: #2FA0BB;
- font-weight: bold;
-}
-
-.author {
- color: #999;
-}
-
-
-
-
-.dark_scheme_box {
- padding:20px 0;
-
- label {
- float:left;
- box-shadow: 0 0px 5px rgba(0,0,0,.3);
-
- img {
- }
- }
-}
-
-a.project-update.titled {
- position: relative;
- padding-left: 235px !important;
-
- .title-block {
- padding: 10px;
- width: 205px;
- position: absolute;
- left: 0;
- top: 0;
- }
-}
-
-.add_new {
- float: right;
- background: #A6B807;
- color: white;
- padding: 4px 10px;
- @include round-borders-all(4px);
- font-size:11px;
- margin: 10px 0;
-}
diff --git a/app/assets/stylesheets/ref_select.scss b/app/assets/stylesheets/ref_select.scss
index 6f6a1bc9..ed6760f1 100644
--- a/app/assets/stylesheets/ref_select.scss
+++ b/app/assets/stylesheets/ref_select.scss
@@ -12,37 +12,45 @@
width:120px;
}
-.project-refs-form .chzn-container {
+.project-refs-form .chzn-container {
position: relative;
top: 0;
left: 0;
margin-right: 10px;
- .chzn-drop {
+ .chzn-drop {
margin:7px 0;
- border: 1px solid #CCC;
- min-width: 300px;
+ min-width: 400px;
+ border: 2px solid $blue_link;
+ @include border-radius(4px);
- .chzn-results {
+ .chzn-results {
max-height:300px;
+
+ .group-result {
+ color: $blue_link;
+ }
+ .active-result {
+ &.highlighted {
+ background: $blue_link;
+ }
+ }
}
.chzn-search input {
- min-width:200px;
+ min-width:365px;
}
}
- .chzn-single {
- background:#ddd;
- //border:none;
- //box-shadow:none;
+ .chzn-single {
+ @include bg-gray-gradient;
- div {
+ div {
background:transparent;
border-left:none;
}
- span {
+ span {
font-weight: normal;
}
}
diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss
index e2db701d..75e38aee 100644
--- a/app/assets/stylesheets/sections/commits.scss
+++ b/app/assets/stylesheets/sections/commits.scss
@@ -206,4 +206,24 @@
min-width:65px;
font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
}
+
+ .commit-author-name {
+ color: #777;
+ }
+}
+
+.diff_file_header a,
+.file_stats a {
+ color:$style_color;
+}
+
+.file_stats {
+ span {
+ img {
+ width:14px;
+ float:left;
+ margin-right:6px;
+ padding:2px 0;
+ }
+ }
}
diff --git a/app/assets/stylesheets/sections/graph.scss b/app/assets/stylesheets/sections/graph.scss
index 33d91de5..2aa4463e 100644
--- a/app/assets/stylesheets/sections/graph.scss
+++ b/app/assets/stylesheets/sections/graph.scss
@@ -6,11 +6,7 @@
h4 {
padding:0 10px;
border-bottom: 1px solid #bbb;
- background:#eee;
- background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
- background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
+ @include bg-gray-gradient;
}
.graph {
diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss
index d0fb662e..8328a5ab 100644
--- a/app/assets/stylesheets/sections/header.scss
+++ b/app/assets/stylesheets/sections/header.scss
@@ -22,7 +22,7 @@ header {
*
*/
.app_logo {
- width:230px;
+ width:200px;
float:left;
position:relative;
top:-5px;
@@ -31,7 +31,7 @@ header {
h1 {
padding-top: 5px;
- width:102px;
+ width:90px;
background: url('logo_dark.png') no-repeat 0px -3px;
float:left;
margin-left:5px;
diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss
index 1b61ec3f..10def510 100644
--- a/app/assets/stylesheets/sections/issues.scss
+++ b/app/assets/stylesheets/sections/issues.scss
@@ -1,55 +1,55 @@
-.issue_form_box {
+.issue_form_box {
@extend .main_box;
- .issue_title {
+ .issue_title {
@extend .top_box_content;
- .clearfix {
- margin-bottom:0px;
- input {
+ .clearfix {
+ margin-bottom:0px;
+ input {
@extend .span8;
}
}
}
- .issue_middle_block {
+ .issue_middle_block {
@extend .middle_box_content;
height:30px;
- .issue_assignee {
+ .issue_assignee {
@extend .span6;
float:left;
}
- .issue_milestone {
+ .issue_milestone {
@extend .span4;
float:left;
}
}
- .issue_description {
+ .issue_description {
@extend .bottom_box_content;
}
}
-.issues_table {
- .issue {
+.issues_table {
+ .issue {
padding:7px 10px;
- .issue_check {
+ .issue_check {
float:left;
padding: 8px 0;
padding-right: 8px;
min-width: 15px;
}
- p {
+ p {
padding-top:0;
padding-bottom:2px;
}
- img.avatar {
+ img.avatar {
width:32px;
margin-top:4px;
}
}
}
-input.check_all_issues {
+input.check_all_issues {
float:left;
padding: 0;
margin:0;
@@ -59,36 +59,41 @@ input.check_all_issues {
height: 22px;
}
-.issues_content {
- .title {
+.issues_content {
+ .title {
height: 40px;
}
}
-#issues-table-holder {
- .issues_filters {
- form {
- padding:0;
- margin:0;
- margin-top:7px
- }
- }
+@media (min-width: 800px) { .issues_filters select { width:160px; } }
+@media (min-width: 1000px) { .issues_filters select { width:200px; } }
+@media (min-width: 1200px) { .issues_filters select { width:220px; } }
- .issues_bulk_update {
- margin: 0;
- form {
+
+#issues-table-holder {
+ .issues_filters {
+ form {
padding:0;
margin:0;
margin-top:7px
}
- .update_selected_issues {
+ }
+
+ .issues_bulk_update {
+ margin: 0;
+ form {
+ padding:0;
+ margin:0;
+ margin-top:7px
+ }
+ .update_selected_issues {
position:relative;
top:-2px;
margin-left:4px;
float:left;
}
-
- .update_issues_text {
+
+ .update_issues_text {
padding:3px;
line-height: 18px;
float:left;
@@ -96,6 +101,15 @@ input.check_all_issues {
}
}
-#update_status {
+#update_status {
width:100px;
}
+
+
+/**
+ * Milestones list
+ *
+ */
+.milestone {
+ @extend .wll;
+}
diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss
index ec84a64e..c932f0fc 100644
--- a/app/assets/stylesheets/sections/merge_requests.scss
+++ b/app/assets/stylesheets/sections/merge_requests.scss
@@ -1,52 +1,35 @@
-/**
+/**
* MR form
*
*/
-.mr_branch_box {
+.mr_branch_box {
@extend .ui-box;
margin-bottom:20px;
- .body {
+ .body {
background:#f1f1f1;
}
- .commit {
- margin:0;
- padding:0;
- padding: 5px;
- margin-bottom: 5px;
-
- .committed_ago {
- display:none;
- }
- .browse_code_link_holder {
- display:none;
- }
- list-style:none;
- &:hover {
- background:none;
- }
- }
}
/**
* MR -> show: Automerge widget
*
*/
-.automerge_widget {
- &.can_be_merged {
+.automerge_widget {
+ &.can_be_merged {
background: #DFF0D8;
}
- form {
+ form {
margin-bottom:0;
- .clearfix {
+ .clearfix {
margin-bottom:0;
}
}
- .accept_group {
+ .accept_group {
float:left;
border: 1px solid #ADA;
padding: 2px;
@@ -54,28 +37,29 @@
border-radius: 5px;
background: #CEB;
- .accept_merge_request {
+ .accept_merge_request {
+ font-size:13px;
float:left;
}
- .remove_branch_holder {
+ .remove_branch_holder {
margin-left:20px;
margin-right:10px;
float:left;
}
- label {
+ label {
color:#444;
}
}
- .how_to_merge_link {
+ .how_to_merge_link {
@extend .primary;
}
}
-.mr_nav_tabs {
- li {
- a {
+.mr_nav_tabs {
+ li {
+ a {
font-weight:bold;
padding:8px 20px;
text-align:center;
@@ -83,19 +67,57 @@
}
}
-li.merge_request {
+li.merge_request {
padding:7px 10px;
- img.avatar {
+ img.avatar {
width: 32px;
margin-top: 4px;
}
- p {
+ p {
padding: 0px;
padding-bottom: 2px;
}
}
-.merge_in_progress {
+.merge_in_progress {
@extend .padded;
@extend .append-bottom-10;
}
+
+.label_branch {
+ @include round-borders-all(4px);
+ padding:2px 4px;
+ border:none;
+ font-size:14px;
+ background: #474D57;
+ color:#fff;
+ font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
+}
+
+.mr_source_commit,
+.mr_target_commit {
+ .commit {
+ margin:0;
+ padding:0;
+ padding: 5px;
+ margin-bottom: 5px;
+ .avatar { position:relative }
+ .row_title {
+ color:#444;
+ }
+ .commit-author-name,
+ .dash,
+ .committed_ago,
+ .browse_code_link_holder {
+ display:none;
+ }
+ list-style:none;
+ &:hover {
+ background:none;
+ }
+ }
+}
+
+.mr_direction_tip {
+ margin-top:40px
+}
diff --git a/app/assets/stylesheets/sections/nav.scss b/app/assets/stylesheets/sections/nav.scss
index 4a773644..2d902918 100644
--- a/app/assets/stylesheets/sections/nav.scss
+++ b/app/assets/stylesheets/sections/nav.scss
@@ -2,21 +2,17 @@
* Main Menu of Application
*
*/
-ul.main_menu {
+ul.main_menu {
border-radius: 4px;
margin: auto;
margin:30px 0;
- background:#eee;
- border:1px solid #bbb;
+ border:1px solid #AAA;
height:37px;
- background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
- background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
+ @include bg-gray-gradient;
position:relative;
overflow:hidden;
@include shade;
- .count {
+ .count {
position: relative;
top: -1px;
display: inline-block;
@@ -33,12 +29,12 @@ ul.main_menu {
border-radius: 8px;
-moz-border-radius: 8px;
}
- .label {
+ .label {
background:$hover;
text-shadow:none;
color:$style_color;
}
- li {
+ li {
list-style-type: none;
margin: 0;
display: table-cell;
@@ -47,7 +43,7 @@ ul.main_menu {
border-left: 1px solid #EEE;
border-bottom:2px solid #CFCFCF;
- &:first-child{
+ &:first-child{
-webkit-border-top-left-radius: 4px;
-webkit-border-bottom-left-radius: 4px;
-moz-border-radius-topleft: 4px;
@@ -57,31 +53,30 @@ ul.main_menu {
border-left: 0;
}
- &.current {
+ &.current {
background-color:#D5D5D5;
- border-bottom: 2px solid $style_color;
border-right: 1px solid #BBB;
border-left: 1px solid #BBB;
border-radius: 0 0 1px 1px;
- &:first-child{
+ &:first-child{
border-bottom:none;
border-left:none;
}
}
- &.home {
- a {
+ &.home {
+ a {
background: url(home_icon.PNG) no-repeat center center;
text-indent:-9999px;
min-width:20px;
- img {
+ img {
position:relative;
top:4px;
}
}
}
}
- a {
+ a {
display: block;
text-align: center;
font-weight:bold;
@@ -89,7 +84,7 @@ ul.main_menu {
line-height:36px;
color: $style_color;
text-shadow:0 1px 1px white;
-
+ padding:0 10px;
}
}
/*
diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss
index 30587ef5..267a9b43 100644
--- a/app/assets/stylesheets/sections/notes.scss
+++ b/app/assets/stylesheets/sections/notes.scss
@@ -2,18 +2,14 @@
* Notes
*
*/
-#notes-list,
-#new_notes_list {
+#notes-list,
+#new-notes-list {
display:block;
list-style:none;
margin:0px;
padding:0px;
}
-#new_notes_list li:last-child{
- border-bottom:1px solid #aaa;
-}
-
.issue_notes,
.wiki_notes {
.note_content {
@@ -30,17 +26,21 @@
}
#new_note {
- #note_note {
- height:25px;
- }
.attach_holder {
display:none;
}
}
-.note {
- padding: 8px 0;
- border-bottom: 1px solid #eee;
+.preview_note {
+ margin: 2px;
+ border: 1px solid #ddd;
+ padding: 10px;
+ min-height: 60px;
+ background:#f5f5f5;
+}
+
+.note {
+ padding: 8px 0;
overflow: hidden;
display: block;
img {float: left; margin-right: 10px;}
@@ -49,19 +49,36 @@
.note-author { color: $style_color;}
.note-title { margin-left:45px; padding-top: 5px;}
- .avatar {
+ .avatar {
margin-top:3px;
}
- .delete-note {
- display:none;
+ .delete-note {
+ display:none;
float:right;
}
- &:hover {
+ &:hover {
.delete-note { display:block; }
}
}
+#notes-list:not(.reversed) .note,
+#new-notes-list:not(.reversed) .note {
+ border-bottom: 1px solid #eee;
+}
+#notes-list.reversed .note,
+#new-notes-list.reversed .note {
+ border-top: 1px solid #eee;
+}
+
+/* mark vote notes */
+.voting_notes .note {
+ padding: 8px 0;
+}
+
+.notes-status {
+ margin: 18px;
+}
p.notify_controls input{
@@ -72,18 +89,18 @@ p.notify_controls span{
font-weight: 700;
}
-tr.line_notes_row {
+tr.line_notes_row {
border-bottom:1px solid #DDD;
border-left: 7px solid #2A79A3;
- &.reply {
+ &.reply {
background:#eee;
border-left: 7px solid #2A79A3;
border-top:1px solid #ddd;
- td {
+ td {
padding:7px 10px;
}
- a.line_note_reply_link {
+ a.line_note_reply_link {
@include round-borders-all(4px);
padding: 3px 10px;
margin-left:5px;
@@ -92,9 +109,9 @@ tr.line_notes_row {
border-color: #2A79A3;
}
}
- ul {
+ ul {
margin:0;
- li {
+ li {
padding:0;
border:none;
}
@@ -103,26 +120,26 @@ tr.line_notes_row {
.line_notes_row, .per_line_form { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; }
-.per_line_form {
+.per_line_form {
background:#f5f5f5;
border-top:1px solid #eee;
form { margin: 0; }
- td {
+ td {
border-bottom:1px solid #ddd;
}
- .note_actions {
+ .note_actions {
margin:0;
padding-top: 10px;
- .buttons {
+ .buttons {
float:left;
width:300px;
}
- .options {
- .labels {
+ .options {
+ .labels {
float:left;
padding-left:10px;
- label {
+ label {
padding: 6px 0;
margin: 0;
width:120px;
@@ -132,7 +149,7 @@ tr.line_notes_row {
}
}
-td .line_note_link {
+td .line_note_link {
position:absolute;
margin-left:-70px;
margin-top:-10px;
@@ -144,14 +161,14 @@ td .line_note_link {
opacity: 0.0;
filter: alpha(opacity=0);
- &:hover {
+ &:hover {
opacity: 1.0;
filter: alpha(opacity=100);
}
}
.diff_file_content tr.line_holder:hover > td { background: $hover !important; }
-.diff_file_content tr.line_holder:hover > td .line_note_link {
+.diff_file_content tr.line_holder:hover > td .line_note_link {
opacity: 1.0;
filter: alpha(opacity=100);
}
@@ -169,8 +186,8 @@ td .line_note_link {
margin: 0;
}
- .note_advanced_opts {
- h6 {
+ .note_advanced_opts {
+ h6 {
line-height: 32px;
padding-right: 15px;
}
@@ -183,7 +200,7 @@ td .line_note_link {
overflow:hidden;
margin:0 0 5px !important;
- .input_file {
+ .input_file {
.file_upload {
position: absolute;
right:14px;
@@ -196,7 +213,7 @@ td .line_note_link {
height:28px;
overflow:hidden;
}
- .input-file {
+ .input-file {
width: 260px;
height: 41px;
float: right;
@@ -204,3 +221,8 @@ td .line_note_link {
}
}
}
+
+.note-text {
+ border: 1px solid #aaa;
+ box-shadow:none;
+}
diff --git a/app/assets/stylesheets/sections/profile.scss b/app/assets/stylesheets/sections/profile.scss
new file mode 100644
index 00000000..206da3a9
--- /dev/null
+++ b/app/assets/stylesheets/sections/profile.scss
@@ -0,0 +1,8 @@
+.profile_history {
+ .event_feed {
+ min-height:20px;
+ .avatar {
+ width:20px;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss
index 0866b43f..92d0fc43 100644
--- a/app/assets/stylesheets/sections/projects.scss
+++ b/app/assets/stylesheets/sections/projects.scss
@@ -14,6 +14,32 @@
text-shadow: 0 1px 1px #fff;
padding: 2px 10px;
}
+ ul {
+ li {
+ padding:0;
+ a {
+ display:block;
+ .project_name {
+ color:#4fa2bd;
+ font-size:14px;
+ line-height:18px;
+ }
+ .arrow {
+ float:right;
+ padding:10px;
+ margin:0;
+ }
+ .last_activity {
+ padding-top:5px;
+ display:block;
+ span, strong {
+ font-size:12px;
+ color:#666;
+ }
+ }
+ }
+ }
+ }
@extend .leftbar;
@extend .ui-box;
}
@@ -33,9 +59,38 @@
color:#888;
}
.btn {
- padding:6px;
+ padding:6px 10px;
margin-left:10px;
margin-bottom:8px;
}
}
+ .adv_settings {
+ h6 { margin-left:40px; }
+ }
+}
+
+.project_clone_panel {
+ @include border-radius(4px);
+ @include bg-gray-gradient;
+ padding: 4px 7px;
+ border: 1px solid #CCC;
+ margin-bottom:5px;
+}
+
+.project_clone_holder {
+ input[type="text"] {
+ border: 1px solid #BBB;
+ box-shadow: none;
+ }
+}
+
+.save-project-loader {
+ img {
+ margin-top:50px;
+ margin-bottom:50px;
+ }
+ h3 {
+ @extend .page_title;
+ }
+
}
diff --git a/app/assets/stylesheets/sections/tree.scss b/app/assets/stylesheets/sections/tree.scss
index 2663fc9a..07568706 100644
--- a/app/assets/stylesheets/sections/tree.scss
+++ b/app/assets/stylesheets/sections/tree.scss
@@ -1,4 +1,4 @@
-#tree-holder {
+#tree-holder {
#tree-content-holder {
float:left;
width:100%;
@@ -11,40 +11,44 @@
padding:12px;
background: #F7F7F7;
- pre {
+ pre {
overflow: auto;
}
}
}
- .tree_progress {
+ .tree_progress {
display:none;
margin:20px;
- &.loading {
+ &.loading {
display:block;
}
}
#tree-slider {
@include border-radius(0);
- .tree-item {
- &:hover {
- td { background: $hover; }
+ .tree-item {
+ &:hover {
+ td {
+ background: $hover;
+ border-top:1px solid #FEA;
+ border-bottom:1px solid #FEA;
+ }
cursor:pointer;
}
}
}
- .tree-item {
- .tree-item-file-name {
+ .tree-item {
+ .tree-item-file-name {
vertical-align:middle;
- a {
- &:hover {
+ a {
+ &:hover {
color:$blue_link;
}
}
- img {
+ img {
position: relative;
top:-1px;
}
@@ -52,41 +56,19 @@
}
- #tree-slider {
- @include solid_shade;
- width:100%;
-
- border-color:#ccc;
-
- td {
- padding:8px;
- border-color:#f1f1f1;
+ #tree-slider {
+ td {
background:#fafafa;
}
-
- tr:first-child td:first-child,
- tr:first-child td:last-child {
- border-radius:0;
- }
-
- th {
- border-color: #CCC;
- border-bottom: 1px solid #bbb;
- background:#eee;
- background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
- background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
- }
}
- .tree-commit-link {
+ .tree-commit-link {
color:#333;
}
- a.tree-commit-link {
+ a.tree-commit-link {
color: #666;
- &:hover {
+ &:hover {
text-decoration: underline;
}
}
diff --git a/app/contexts/merge_requests_load.rb b/app/contexts/merge_requests_load.rb
index 6778db3b..e2f68e38 100644
--- a/app/contexts/merge_requests_load.rb
+++ b/app/contexts/merge_requests_load.rb
@@ -1,13 +1,13 @@
class MergeRequestsLoad < BaseContext
def execute
- type = params[:f].to_i
+ type = params[:f]
merge_requests = project.merge_requests
merge_requests = case type
- when 1 then merge_requests
- when 2 then merge_requests.closed
- when 3 then merge_requests.opened.assigned(current_user)
+ when 'all' then merge_requests
+ when 'closed' then merge_requests.closed
+ when 'assigned-to-me' then merge_requests.opened.assigned(current_user)
else merge_requests.opened
end.page(params[:page]).per(20)
diff --git a/app/contexts/notes/load_context.rb b/app/contexts/notes/load_context.rb
index c89a7d19..f92a7801 100644
--- a/app/contexts/notes/load_context.rb
+++ b/app/contexts/notes/load_context.rb
@@ -3,30 +3,31 @@ module Notes
def execute
target_type = params[:target_type]
target_id = params[:target_id]
- first_id = params[:first_id]
- last_id = params[:last_id]
+ after_id = params[:after_id]
+ before_id = params[:before_id]
@notes = case target_type
- when "commit"
- then project.commit_notes(project.commit(target_id)).fresh.limit(20)
- when "snippet"
- then project.snippets.find(target_id).notes
- when "wall"
- then project.common_notes.order("created_at DESC").fresh.limit(50)
+ when "commit"
+ project.commit_notes(project.commit(target_id)).fresh.limit(20)
when "issue"
- then project.issues.find(target_id).notes.inc_author.order("created_at DESC").limit(20)
+ project.issues.find(target_id).notes.inc_author.fresh.limit(20)
when "merge_request"
- then project.merge_requests.find(target_id).notes.inc_author.order("created_at DESC").limit(20)
+ project.merge_requests.find(target_id).notes.inc_author.fresh.limit(20)
+ when "snippet"
+ project.snippets.find(target_id).notes.fresh
+ when "wall"
+ # this is the only case, where the order is DESC
+ project.common_notes.order("created_at DESC, id DESC").limit(50)
when "wiki"
- then project.wikis.reverse.map {|w| w.notes.fresh }.flatten[0..20]
+ project.wiki_notes.limit(20)
end
- @notes = if last_id
- @notes.where("id > ?", last_id)
- elsif first_id
- @notes.where("id < ?", first_id)
- else
+ @notes = if after_id
+ @notes.where("id > ?", after_id)
+ elsif before_id
+ @notes.where("id < ?", before_id)
+ else
@notes
end
end
diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb
index ad80f4d5..5152f6fa 100644
--- a/app/controllers/admin/dashboard_controller.rb
+++ b/app/controllers/admin/dashboard_controller.rb
@@ -1,8 +1,4 @@
-class Admin::DashboardController < ApplicationController
- layout "admin"
- before_filter :authenticate_user!
- before_filter :authenticate_admin!
-
+class Admin::DashboardController < AdminController
def index
@workers = Resque.workers
@pending_jobs = Resque.size(:post_receive)
diff --git a/app/controllers/admin/hooks_controller.rb b/app/controllers/admin/hooks_controller.rb
index 7f832fd5..91a1d633 100644
--- a/app/controllers/admin/hooks_controller.rb
+++ b/app/controllers/admin/hooks_controller.rb
@@ -1,8 +1,4 @@
-class Admin::HooksController < ApplicationController
- layout "admin"
- before_filter :authenticate_user!
- before_filter :authenticate_admin!
-
+class Admin::HooksController < AdminController
def index
@hooks = SystemHook.all
@hook = SystemHook.new
@@ -15,7 +11,7 @@ class Admin::HooksController < ApplicationController
redirect_to admin_hooks_path, notice: 'Hook was successfully created.'
else
@hooks = SystemHook.all
- render :index
+ render :index
end
end
diff --git a/app/controllers/admin/logs_controller.rb b/app/controllers/admin/logs_controller.rb
index c130b4b8..28c321a9 100644
--- a/app/controllers/admin/logs_controller.rb
+++ b/app/controllers/admin/logs_controller.rb
@@ -1,6 +1,2 @@
-class Admin::LogsController < ApplicationController
- layout "admin"
- before_filter :authenticate_user!
- before_filter :authenticate_admin!
+class Admin::LogsController < AdminController
end
-
diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb
index 80d11f03..24406525 100644
--- a/app/controllers/admin/projects_controller.rb
+++ b/app/controllers/admin/projects_controller.rb
@@ -1,7 +1,4 @@
-class Admin::ProjectsController < ApplicationController
- layout "admin"
- before_filter :authenticate_user!
- before_filter :authenticate_admin!
+class Admin::ProjectsController < AdminController
before_filter :admin_project, only: [:edit, :show, :update, :destroy, :team_update]
def index
@@ -43,7 +40,7 @@ class Admin::ProjectsController < ApplicationController
def update
owner_id = params[:project].delete(:owner_id)
- if owner_id
+ if owner_id
@admin_project.owner = User.find(owner_id)
end
@@ -60,7 +57,7 @@ class Admin::ProjectsController < ApplicationController
redirect_to admin_projects_url, notice: 'Project was successfully deleted.'
end
- private
+ private
def admin_project
@admin_project = Project.find_by_code(params[:id])
diff --git a/app/controllers/admin/resque_controller.rb b/app/controllers/admin/resque_controller.rb
index dc575cc2..9d8e7e30 100644
--- a/app/controllers/admin/resque_controller.rb
+++ b/app/controllers/admin/resque_controller.rb
@@ -1,5 +1,4 @@
-class Admin::ResqueController < ApplicationController
- layout 'admin'
+class Admin::ResqueController < AdminController
def show
end
-end
\ No newline at end of file
+end
diff --git a/app/controllers/admin/team_members_controller.rb b/app/controllers/admin/team_members_controller.rb
index 57803b01..07320805 100644
--- a/app/controllers/admin/team_members_controller.rb
+++ b/app/controllers/admin/team_members_controller.rb
@@ -1,8 +1,4 @@
-class Admin::TeamMembersController < ApplicationController
- layout "admin"
- before_filter :authenticate_user!
- before_filter :authenticate_admin!
-
+class Admin::TeamMembersController < AdminController
def edit
@admin_team_member = UsersProject.find(params[:id])
end
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 1e8f420b..e2d61864 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -1,8 +1,4 @@
-class Admin::UsersController < ApplicationController
- layout "admin"
- before_filter :authenticate_user!
- before_filter :authenticate_admin!
-
+class Admin::UsersController < AdminController
def index
@admin_users = User.scoped
@admin_users = @admin_users.filter(params[:filter])
@@ -24,7 +20,7 @@ class Admin::UsersController < ApplicationController
@admin_user = User.find(params[:id])
UsersProject.user_bulk_import(
- @admin_user,
+ @admin_user,
params[:project_ids],
params[:project_access]
)
@@ -41,22 +37,22 @@ class Admin::UsersController < ApplicationController
@admin_user = User.find(params[:id])
end
- def block
+ def block
@admin_user = User.find(params[:id])
if @admin_user.block
redirect_to :back, alert: "Successfully blocked"
- else
+ else
redirect_to :back, alert: "Error occured. User was not blocked"
end
end
- def unblock
+ def unblock
@admin_user = User.find(params[:id])
if @admin_user.update_attribute(:blocked, false)
redirect_to :back, alert: "Successfully unblocked"
- else
+ else
redirect_to :back, alert: "Error occured. User was not unblocked"
end
end
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb
new file mode 100644
index 00000000..bce9f692
--- /dev/null
+++ b/app/controllers/admin_controller.rb
@@ -0,0 +1,11 @@
+# Provides a base class for Admin controllers to subclass
+#
+# Automatically sets the layout and ensures an administrator is logged in
+class AdminController < ApplicationController
+ layout 'admin'
+ before_filter :authenticate_admin!
+
+ def authenticate_admin!
+ return render_404 unless current_user.is_admin?
+ end
+end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 7c1941ec..5ac5c639 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -11,11 +11,11 @@ class ApplicationController < ActionController::Base
helper_method :abilities, :can?
rescue_from Gitlab::Gitolite::AccessDenied do |exception|
- render "errors/gitolite", layout: "error"
+ render "errors/gitolite", layout: "error", status: 500
end
rescue_from Encoding::CompatibilityError do |exception|
- render "errors/encoding", layout: "error", status: 404
+ render "errors/encoding", layout: "error", status: 500
end
rescue_from ActiveRecord::RecordNotFound do |exception|
@@ -84,10 +84,6 @@ class ApplicationController < ActionController::Base
abilities << Ability
end
- def authenticate_admin!
- return render_404 unless current_user.is_admin?
- end
-
def authorize_project!(action)
return access_denied! unless can?(current_user, action, project)
end
@@ -116,22 +112,12 @@ class ApplicationController < ActionController::Base
end
end
- def load_refs
- if params[:ref].blank?
- @branch = params[:branch].blank? ? nil : params[:branch]
- @tag = params[:tag].blank? ? nil : params[:tag]
- @ref = @branch || @tag || @project.try(:default_branch) || Repository.default_ref
- else
- @ref = params[:ref]
- end
- end
-
def render_404
render file: File.join(Rails.root, "public", "404"), layout: false, status: "404"
end
def require_non_empty_project
- redirect_to @project unless @project.repo_exists? && @project.has_commits?
+ redirect_to @project if @project.empty_repo?
end
def no_cache_headers
diff --git a/app/controllers/commits_controller.rb b/app/controllers/commits_controller.rb
index 717912d9..1e7aec00 100644
--- a/app/controllers/commits_controller.rb
+++ b/app/controllers/commits_controller.rb
@@ -52,6 +52,7 @@ class CommitsController < ApplicationController
@commits = result[:commits]
@commit = result[:commit]
@diffs = result[:diffs]
+ @refs_are_same = result[:same]
@line_notes = []
@commits = CommitDecorator.decorate(@commits)
@@ -59,12 +60,19 @@ class CommitsController < ApplicationController
def patch
@commit = project.commit(params[:id])
-
+
send_data(
@commit.to_patch,
type: "text/plain",
disposition: 'attachment',
- filename: (@commit.id.to_s + ".patch")
+ filename: "#{@commit.id}.patch"
)
end
+
+ protected
+
+ def load_refs
+ @ref ||= params[:ref].presence || params[:branch].presence || params[:tag].presence
+ @ref ||= @ref || @project.try(:default_branch) || 'master'
+ end
end
diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb
index 889a7d98..1d78a6d9 100644
--- a/app/controllers/issues_controller.rb
+++ b/app/controllers/issues_controller.rb
@@ -17,7 +17,7 @@ class IssuesController < ApplicationController
before_filter :authorize_write_issue!, only: [:new, :create]
# Allow modify issue
- before_filter :authorize_modify_issue!, only: [:close, :edit, :update]
+ before_filter :authorize_modify_issue!, only: [:edit, :update]
# Allow destroy issue
before_filter :authorize_admin_issue!, only: [:destroy]
@@ -37,7 +37,7 @@ class IssuesController < ApplicationController
end
def new
- @issue = @project.issues.new
+ @issue = @project.issues.new(params[:issue])
respond_with(@issue)
end
@@ -60,7 +60,13 @@ class IssuesController < ApplicationController
@issue.save
respond_to do |format|
- format.html { redirect_to project_issue_path(@project, @issue) }
+ format.html do
+ if @issue.valid?
+ redirect_to project_issue_path(@project, @issue)
+ else
+ render :new
+ end
+ end
format.js
end
end
@@ -81,8 +87,6 @@ class IssuesController < ApplicationController
end
def destroy
- return access_denied! unless can?(current_user, :admin_issue, @issue)
-
@issue.destroy
respond_to do |format|
@@ -162,10 +166,10 @@ class IssuesController < ApplicationController
def issues_filter
{
- all: "1",
- closed: "2",
- to_me: "3",
- open: "0"
+ all: "all",
+ closed: "closed",
+ to_me: "assigned-to-me",
+ open: "open"
}
end
end
diff --git a/app/controllers/labels_controller.rb b/app/controllers/labels_controller.rb
new file mode 100644
index 00000000..e703f822
--- /dev/null
+++ b/app/controllers/labels_controller.rb
@@ -0,0 +1,25 @@
+class LabelsController < ApplicationController
+ before_filter :authenticate_user!
+ before_filter :project
+ before_filter :module_enabled
+
+ layout "project"
+
+ # Authorize
+ before_filter :add_project_abilities
+
+ # Allow read any issue
+ before_filter :authorize_read_issue!
+
+ respond_to :js, :html
+
+ def index
+ @labels = @project.issues.tag_counts_on(:labels).order('count DESC')
+ end
+
+ protected
+
+ def module_enabled
+ return render_404 unless @project.issues_enabled
+ end
+end
diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb
index 4938a294..187bb407 100644
--- a/app/controllers/merge_requests_controller.rb
+++ b/app/controllers/merge_requests_controller.rb
@@ -103,10 +103,12 @@ class MergeRequestsController < ApplicationController
def branch_from
@commit = project.commit(params[:ref])
+ @commit = CommitDecorator.decorate(@commit)
end
def branch_to
@commit = project.commit(params[:ref])
+ @commit = CommitDecorator.decorate(@commit)
end
protected
diff --git a/app/controllers/milestones_controller.rb b/app/controllers/milestones_controller.rb
index 7acb3781..10f089f1 100644
--- a/app/controllers/milestones_controller.rb
+++ b/app/controllers/milestones_controller.rb
@@ -17,8 +17,8 @@ class MilestonesController < ApplicationController
respond_to :html
def index
- @milestones = case params[:f].to_i
- when 1; @project.milestones
+ @milestones = case params[:f]
+ when 'all'; @project.milestones
else @project.milestones.active
end
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index d472936b..2fb783b2 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -1,4 +1,9 @@
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
+ Gitlab.config.omniauth_providers.each do |provider|
+ define_method provider['name'] do
+ handle_omniauth
+ end
+ end
# Extend the standard message generation to accept our custom exception
def failure_message
@@ -9,7 +14,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
error ||= env["omniauth.error.type"].to_s
error.to_s.humanize if error
end
-
+
def ldap
# We only find ourselves here if the authentication to LDAP was successful.
@user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user)
@@ -19,4 +24,27 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
sign_in_and_redirect @user
end
+ private
+
+ def handle_omniauth
+ oauth = request.env['omniauth.auth']
+ provider, uid = oauth['provider'], oauth['uid']
+
+ if current_user
+ # Change a logged-in user's authentication method:
+ current_user.extern_uid = uid
+ current_user.provider = provider
+ current_user.save
+ redirect_to profile_path
+ else
+ @user = User.find_or_new_for_omniauth(oauth)
+
+ if @user
+ sign_in_and_redirect @user
+ else
+ flash[:notice] = "There's no such user!"
+ redirect_to new_user_session_path
+ end
+ end
+ end
end
diff --git a/app/controllers/profile_controller.rb b/app/controllers/profile_controller.rb
index a95a3310..7ddbfe11 100644
--- a/app/controllers/profile_controller.rb
+++ b/app/controllers/profile_controller.rb
@@ -16,9 +16,6 @@ class ProfileController < ApplicationController
def token
end
- def password
- end
-
def password_update
params[:user].reject!{ |k, v| k != "password" && k != "password_confirmation"}
@@ -32,10 +29,14 @@ class ProfileController < ApplicationController
def reset_private_token
current_user.reset_authentication_token!
- redirect_to profile_token_path
+ redirect_to profile_account_path
end
- private
+ def history
+ @events = current_user.recent_events.page(params[:page]).per(20)
+ end
+
+ private
def user
@user = current_user
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index bd7f811e..170b8892 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -50,7 +50,7 @@ class ProjectsController < ApplicationController
respond_to do |format|
format.html do
- if @project.repo_exists? && @project.has_commits?
+ unless @project.empty_repo?
@last_push = current_user.recent_push(@project.id)
render :show
else
diff --git a/app/controllers/refs_controller.rb b/app/controllers/refs_controller.rb
index 3f81a2ca..90361437 100644
--- a/app/controllers/refs_controller.rb
+++ b/app/controllers/refs_controller.rb
@@ -1,3 +1,5 @@
+require 'github/markup'
+
class RefsController < ApplicationController
include Gitlab::Encode
before_filter :project
diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb
index 0846f096..a50dcd3e 100644
--- a/app/controllers/team_members_controller.rb
+++ b/app/controllers/team_members_controller.rb
@@ -5,7 +5,10 @@ class TeamMembersController < ApplicationController
# Authorize
before_filter :add_project_abilities
before_filter :authorize_read_project!
- before_filter :authorize_admin_project!, except: [:show]
+ before_filter :authorize_admin_project!, except: [:index, :show]
+
+ def index
+ end
def show
@team_member = project.users_projects.find(params[:id])
@@ -17,13 +20,12 @@ class TeamMembersController < ApplicationController
end
def create
- @team_member = UsersProject.new(params[:team_member])
- @team_member.project = project
- if @team_member.save
- redirect_to team_project_path(@project)
- else
- render "new"
- end
+ @project.add_users_ids_to_team(
+ params[:user_ids],
+ params[:project_access]
+ )
+
+ redirect_to project_team_index_path(@project)
end
def update
@@ -33,7 +35,7 @@ class TeamMembersController < ApplicationController
unless @team_member.valid?
flash[:alert] = "User should have at least one role"
end
- redirect_to team_project_path(@project)
+ redirect_to project_team_index_path(@project)
end
def destroy
@@ -41,7 +43,7 @@ class TeamMembersController < ApplicationController
@team_member.destroy
respond_to do |format|
- format.html { redirect_to team_project_path(@project) }
+ format.html { redirect_to project_team_index_path(@project) }
format.js { render nothing: true }
end
end
diff --git a/app/decorators/commit_decorator.rb b/app/decorators/commit_decorator.rb
index cc8fa975..c85f7400 100644
--- a/app/decorators/commit_decorator.rb
+++ b/app/decorators/commit_decorator.rb
@@ -1,12 +1,23 @@
class CommitDecorator < ApplicationDecorator
decorates :commit
+ # Returns a string describing the commit for use in a link title
+ #
+ # Example
+ #
+ # "Commit: Alex Denisov - Project git clone panel"
+ def link_title
+ "Commit: #{author_name} - #{title}"
+ end
+
# Returns the commits title.
#
# Usually, the commit title is the first line of the commit message.
# In case this first line is longer than 80 characters, it is cut off
# after 70 characters and ellipses (`&hellp;`) are appended.
def title
+ return no_commit_message if safe_message.blank?
+
title_end = safe_message.index(/\n/)
if (!title_end && safe_message.length > 80) || (title_end && title_end > 80)
safe_message[0..69] << "…".html_safe
@@ -26,4 +37,10 @@ class CommitDecorator < ApplicationDecorator
safe_message.split(/\n/, 2)[1].try(:chomp)
end
end
+
+ protected
+
+ def no_commit_message
+ "--no commit message"
+ end
end
diff --git a/app/decorators/event_decorator.rb b/app/decorators/event_decorator.rb
index 7df9081f..ce0aaa03 100644
--- a/app/decorators/event_decorator.rb
+++ b/app/decorators/event_decorator.rb
@@ -8,7 +8,9 @@ class EventDecorator < ApplicationDecorator
"#{self.author_name} #{self.action_name} MR ##{self.target_id}:" + self.merge_request_title
elsif self.push?
"#{self.author_name} #{self.push_action_name} #{self.ref_type} " + self.ref_name
- else
+ elsif self.membership_changed?
+ "#{self.author_name} #{self.action_name} #{self.project.name}"
+ else
""
end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 38191f55..0938dc23 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -62,7 +62,7 @@ module ApplicationHelper
{ label: "#{@project.name} / Wall", url: wall_project_path(@project) },
{ label: "#{@project.name} / Tree", url: tree_project_ref_path(@project, @project.root_ref) },
{ label: "#{@project.name} / Commits", url: project_commits_path(@project) },
- { label: "#{@project.name} / Team", url: team_project_path(@project) }
+ { label: "#{@project.name} / Team", url: project_team_index_path(@project) }
]
end
@@ -78,16 +78,16 @@ module ApplicationHelper
end
def show_last_push_widget?(event)
- event &&
+ event &&
event.last_push_to_non_root? &&
!event.rm_ref? &&
- event.project &&
+ event.project &&
event.project.merge_requests_enabled
end
def tab_class(tab_key)
active = case tab_key
-
+
# Project Area
when :wall; wall_tab?
when :wiki; controller.controller_name == "wikis"
@@ -104,7 +104,8 @@ module ApplicationHelper
# Profile Area
when :profile; current_page?(controller: "profile", action: :show)
- when :password; current_page?(controller: "profile", action: :password)
+ when :history; current_page?(controller: "profile", action: :history)
+ when :account; current_page?(controller: "profile", action: :account)
when :token; current_page?(controller: "profile", action: :token)
when :design; current_page?(controller: "profile", action: :design)
when :ssh_keys; controller.controller_name == "keys"
@@ -126,4 +127,19 @@ module ApplicationHelper
def hexdigest(string)
Digest::SHA1.hexdigest string
end
+
+ def project_last_activity project
+ activity = project.last_activity
+ if activity && activity.created_at
+ time_ago_in_words(activity.created_at) + " ago"
+ else
+ "Never"
+ end
+ end
+
+ def authbutton(provider, size = 64)
+ file_name = "#{provider.to_s.split('_').first}_#{size}.png"
+ image_tag("authbuttons/#{file_name}",
+ alt: "Sign in with #{provider.to_s.titleize}")
+ end
end
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 88e3473b..111982e9 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -1,38 +1,5 @@
module GitlabMarkdownHelper
- # Replaces references (i.e. @abc, #123, !456, ...) in the text with links to
- # the appropriate items in Gitlab.
- #
- # text - the source text
- # html_options - extra options for the reference links as given to link_to
- #
- # note: reference links will only be generated if @project is set
- #
- # see Gitlab::Markdown for details on the supported syntax
- def gfm(text, html_options = {})
- return text if text.nil?
- return text if @project.nil?
-
- # Extract pre blocks so they are not altered
- # from http://github.github.com/github-flavored-markdown/
- extractions = {}
- text.gsub!(%r{
.*?|
.*?
}m) do |match|
- md5 = Digest::MD5.hexdigest(match)
- extractions[md5] = match
- "{gfm-extraction-#{md5}}"
- end
-
- # TODO: add popups with additional information
-
- parser = Gitlab::Markdown.new(@project, html_options)
- text = parser.parse(text)
-
- # Insert pre block extractions
- text.gsub!(/\{gfm-extraction-(\h{32})\}/) do
- extractions[$1]
- end
-
- text.html_safe
- end
+ include Gitlab::Markdown
# Use this in places where you would normally use link_to(gfm(...), ...).
#
@@ -44,7 +11,9 @@ module GitlabMarkdownHelper
# explicitly produce the correct linking behavior (i.e.
# "outer text gfm ref more outer text").
def link_to_gfm(body, url, html_options = {})
- gfm_body = gfm(body, html_options)
+ return "" if body.blank?
+
+ gfm_body = gfm(escape_once(body), html_options)
gfm_body.gsub!(%r{```
and you won't need to indent manually to trigger a code block.
+
+ %pre= %Q{```ruby\nrequire 'redcarpet'\nmarkdown = Redcarpet.new("Hello World!")\nputs markdown.to_html\n```}
+ %p becomes
+ = markdown %Q{```ruby\nrequire 'redcarpet'\nmarkdown = Redcarpet.new("Hello World!")\nputs markdown.to_html\n```}
+
+ %h4 Emoji
+
+.row
+ .span8
+ :ruby
+ puts markdown %Q{Sometimes you want to be :cool: and add some :sparkles: to your :speech_balloon:. Well we have a :gift: for you:
+
+ :exclamation: You can use emoji anywhere GFM is supported. :sunglasses:
+
+ You can use it to point out a :bug: or warn about :monkey:patches. And if someone improves your really :snail: code, send them a :bouquet: or some :candy:. People will :heart: you for that.
+
+ If you are :new: to this, don't be :fearful:. You can easily join the emoji :circus_tent:. All you need to do is to :book: up on the supported codes.
+ }
+
+ .span4
+ .alert.alert-info
+ %p
+ Consult the
+ %strong= link_to "Emoji Cheat Sheet", "http://www.emoji-cheat-sheet.com/"
+ for a list of all supported emoji codes.
+
+.row
+ .span8
+ %h4 Special GitLab references
+
+ %p
+ GFM recognizes special references.
+ You can easily reference e.g. a team member, an issue or a commit within a project.
+ GFM will turn that reference into a link so you can navigate between them easily.
+
+ %p GFM will recognize the following references:
+ %ul
+ %li
+ %code @foo
+ for team members
+ %li
+ %code #123
+ for issues
+ %li
+ %code !123
+ for merge request
+ %li
+ %code $123
+ for snippets
+ %li
+ %code 1234567
+ for commits
+
+ -# this example will only be shown if the user has a project with at least one issue
+ - if @project = current_user.projects.first
+ - if issue = @project.issues.first
+ %p For example in your #{link_to @project.name, project_path(@project)} project, writing:
+ %pre= "This is related to ##{issue.id}. @#{current_user.name} is working on solving it."
+ %p becomes:
+ = markdown "This is related to ##{issue.id}. @#{current_user.name} is working on solving it."
+ - @project = nil # Prevent this from bubbling up to page title
diff --git a/app/views/help/ssh.html.haml b/app/views/help/ssh.html.haml
index 6a581204..3f082333 100644
--- a/app/views/help/ssh.html.haml
+++ b/app/views/help/ssh.html.haml
@@ -5,7 +5,7 @@
%hr
%p.slead
- SSH key allows you to establish a secure connection between your computer and Gitlab
+ SSH key allows you to establish a secure connection between your computer and GitLab
%p.slead
To generate a new SSH key just open your terminal and use code below.
@@ -17,7 +17,7 @@
\# Generating public/private rsa key pair...
%p.slead
- Next just use code below to dump your public key and add to GITLAB SSH Keys
+ Next just use code below to dump your public key and add to GitLab SSH Keys
%pre.dark
cat ~/.ssh/id_rsa.pub
diff --git a/app/views/help/system_hooks.html.haml b/app/views/help/system_hooks.html.haml
index 9fc8cbab..736c818b 100644
--- a/app/views/help/system_hooks.html.haml
+++ b/app/views/help/system_hooks.html.haml
@@ -5,7 +5,7 @@
%hr
%p.slead
- Your Gitlab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member.
+ Your GitLab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member.
%br
System Hooks can be used for logging or change information in LDAP server.
%br
diff --git a/app/views/help/web_hooks.html.haml b/app/views/help/web_hooks.html.haml
index 263eadf6..65036613 100644
--- a/app/views/help/web_hooks.html.haml
+++ b/app/views/help/web_hooks.html.haml
@@ -5,11 +5,11 @@
%hr
%p.slead
- Every Gitlab project can trigger a web server whenever the repo is pushed to.
+ Every GitLab project can trigger a web server whenever the repo is pushed to.
%br
Web Hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server.
%br
- GITLAB will send POST request with commits information on every push.
+ GitLab will send POST request with commits information on every push.
%h5 Hooks request example:
= render "hooks/data_ex"
diff --git a/app/views/help/workflow.html.haml b/app/views/help/workflow.html.haml
index a3fe3b01..6062ca09 100644
--- a/app/views/help/workflow.html.haml
+++ b/app/views/help/workflow.html.haml
@@ -24,7 +24,7 @@
git commit -am "My feature is ready"
%li
- %p Push your branch to gitlabhq
+ %p Push your branch to GitLab
.bash
%pre.dark
git push origin $feature_name
diff --git a/app/views/hooks/_data_ex.html.erb b/app/views/hooks/_data_ex.html.erb
index 8d3de3f0..7dd6b9e0 100644
--- a/app/views/hooks/_data_ex.html.erb
+++ b/app/views/hooks/_data_ex.html.erb
@@ -32,12 +32,12 @@
:timestamp => "2012-01-03T23:36:29+02:00",
:url => "http://localhost/diaspora/commits/da1560886d...",
:author => {
- :name => "gitlab dev user",
+ :name => "GitLab dev user",
:email => "gitlabdev@dv6700.(none)"
}
}
],
- total_commits_count => 3
+ total_commits_count => 4
}
eos
%>
diff --git a/app/views/hooks/index.html.haml b/app/views/hooks/index.html.haml
index 3d2a381e..1b59c8e8 100644
--- a/app/views/hooks/index.html.haml
+++ b/app/views/hooks/index.html.haml
@@ -26,11 +26,12 @@
Hooks
%small (#{@hooks.count})
%br
- %table.admin-table
- %tr
- %th URL
- %th Method
- %th
+ %table
+ %thead
+ %tr
+ %th URL
+ %th Method
+ %th
- @hooks.each do |hook|
%tr
%td
diff --git a/app/views/issues/_form.html.haml b/app/views/issues/_form.html.haml
index 1b67eabd..813ecab2 100644
--- a/app/views/issues/_form.html.haml
+++ b/app/views/issues/_form.html.haml
@@ -18,12 +18,12 @@
= f.label :assignee_id do
%i.icon-user
Assign to
- .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" })
+ .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }, {class: 'chosen'})
.issue_milestone
= f.label :milestone_id do
%i.icon-time
Milestone
- .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" })
+ .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'})
.issue_description
.clearfix
@@ -38,19 +38,20 @@
= f.label :description, "Details"
.input
= f.text_area :description, maxlength: 2000, class: "xxlarge", rows: 14
- %p.hint Markdown is enabled.
+ %p.hint Issues are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
.actions
- if @issue.new_record?
- = f.submit 'Submit new issue', class: "primary btn"
+ = f.submit 'Submit new issue', class: "btn save-btn"
-else
- = f.submit 'Save changes', class: "primary btn"
+ = f.submit 'Save changes', class: "save-btn btn"
+ - cancel_class = 'btn cancel-btn'
- if request.xhr?
- = link_to "Cancel", "#back", onclick: "backToIssues();", class: "btn"
+ = link_to "Cancel", "#back", onclick: "backToIssues();", class: cancel_class
- else
- if @issue.new_record?
- = link_to "Cancel", project_issues_path(@project), class: "btn"
+ = link_to "Cancel", project_issues_path(@project), class: cancel_class
- else
- = link_to "Cancel", project_issue_path(@project, @issue), class: "btn"
+ = link_to "Cancel", project_issue_path(@project, @issue), class: cancel_class
diff --git a/app/views/issues/_head.html.haml b/app/views/issues/_head.html.haml
index 1f6e7d7f..8ebe3e05 100644
--- a/app/views/issues/_head.html.haml
+++ b/app/views/issues/_head.html.haml
@@ -5,6 +5,9 @@
%li{class: "#{'active' if current_page?(project_milestones_path(@project))}"}
= link_to project_milestones_path(@project), class: "tab" do
Milestones
+ %li{class: "#{'active' if current_page?(project_labels_path(@project))}"}
+ = link_to project_labels_path(@project), class: "tab" do
+ Labels
%li.right
%span.rss-icon
= link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do
diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml
index 8500cd40..64401bdd 100644
--- a/app/views/issues/_show.html.haml
+++ b/app/views/issues/_show.html.haml
@@ -4,7 +4,7 @@
= check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue", disabled: !can?(current_user, :modify_issue, issue)
.right
- issue.labels.each do |label|
- %span.label.label-issue.grouped
+ %span.label.label-tag.grouped
%i.icon-tag
= label.name
- if issue.notes.any?
@@ -34,5 +34,5 @@
- else
- - if issue.upvotes > 0
- %span.badge.badge-success= "+#{issue.upvotes}"
+ - if issue.votes_count > 0
+ = render 'votes/votes_inline', votable: issue
diff --git a/app/views/issues/edit.html.haml b/app/views/issues/edit.html.haml
index 3c9877f8..b1bc3ba0 100644
--- a/app/views/issues/edit.html.haml
+++ b/app/views/issues/edit.html.haml
@@ -1,8 +1 @@
= render "form"
-
-:javascript
- $(function(){
- $('select#issue_assignee_id').chosen();
- $('select#issue_milestone_id').chosen();
- });
-
diff --git a/app/views/issues/index.html.haml b/app/views/issues/index.html.haml
index a6836fd4..22c34baa 100644
--- a/app/views/issues/index.html.haml
+++ b/app/views/issues/index.html.haml
@@ -6,13 +6,13 @@
.right
.span5
- if can? current_user, :write_issue, @project
- = link_to new_project_issue_path(@project), class: "right btn small", title: "New Issue", remote: true do
+ = link_to new_project_issue_path(@project), class: "right btn", title: "New Issue", remote: true, id: "new_issue_link" do
%i.icon-plus
New Issue
= form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do
= hidden_field_tag :project_id, @project.id, { id: 'project_id' }
= hidden_field_tag :status, params[:f]
- = search_field_tag :issue_search, nil, { placeholder: 'Search', class: 'issue_search span3 right neib' }
+ = search_field_tag :issue_search, nil, { placeholder: 'Search', class: 'issue_search span3 right neib search-text-input' }
.clearfix
diff --git a/app/views/issues/new.html.haml b/app/views/issues/new.html.haml
index 3c9877f8..b1bc3ba0 100644
--- a/app/views/issues/new.html.haml
+++ b/app/views/issues/new.html.haml
@@ -1,8 +1 @@
= render "form"
-
-:javascript
- $(function(){
- $('select#issue_assignee_id').chosen();
- $('select#issue_milestone_id').chosen();
- });
-
diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml
index dce8cf6a..da2aeac4 100644
--- a/app/views/issues/show.html.haml
+++ b/app/views/issues/show.html.haml
@@ -8,22 +8,22 @@
%span.right
- if can?(current_user, :admin_project, @project) || @issue.author == current_user
- if @issue.closed
- = link_to 'Reopen', project_issue_path(@project, @issue, issue: {closed: false }, status_only: true), method: :put, class: "btn small"
+ = link_to 'Reopen', project_issue_path(@project, @issue, issue: {closed: false }, status_only: true), method: :put, class: "btn grouped success"
- else
- = link_to 'Close', project_issue_path(@project, @issue, issue: {closed: true }, status_only: true), method: :put, class: "btn small", title: "Close Issue"
+ = link_to 'Close', project_issue_path(@project, @issue, issue: {closed: true }, status_only: true), method: :put, class: "btn grouped danger", title: "Close Issue"
- if can?(current_user, :admin_project, @project) || @issue.author == current_user
- = link_to edit_project_issue_path(@project, @issue), class: "btn small" do
+ = link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do
%i.icon-edit
Edit
- %br
- - if @issue.upvotes > 0
- .upvotes#upvotes= "+#{pluralize @issue.upvotes, 'upvote'}"
+.right
+ .span3#votes= render 'votes/votes_block', votable: @issue
.back_link
= link_to project_issues_path(@project) do
← To issues list
+
.main_box
.top_box_content
%h4
@@ -31,7 +31,7 @@
.alert-message.error.status_info Closed
- else
.alert-message.success.status_info Open
- = gfm @issue.title
+ = gfm escape_once(@issue.title)
.middle_box_content
%cite.cgray Created by
@@ -61,4 +61,4 @@
= markdown @issue.description
-.issue_notes#notes= render "notes/notes", tid: @issue.id, tt: "issue"
+.issue_notes.voting_notes#notes= render "notes/notes_with_form", tid: @issue.id, tt: "issue"
diff --git a/app/views/keys/_form.html.haml b/app/views/keys/_form.html.haml
index 9c6e229b..26700803 100644
--- a/app/views/keys/_form.html.haml
+++ b/app/views/keys/_form.html.haml
@@ -19,6 +19,6 @@
.actions
- = f.submit 'Save', class: "primary btn"
- = link_to "Cancel", keys_path, class: "btn"
+ = f.submit 'Save', class: "btn save-btn"
+ = link_to "Cancel", keys_path, class: "btn cancel-btn"
diff --git a/app/views/keys/index.html.haml b/app/views/keys/index.html.haml
index 04e9e4cb..fd5a9dad 100644
--- a/app/views/keys/index.html.haml
+++ b/app/views/keys/index.html.haml
@@ -1,13 +1,13 @@
%h3.page_title
SSH Keys
- = link_to "Add new", new_key_path, class: "btn small right"
+ = link_to "Add new", new_key_path, class: "btn right"
%hr
-%p.slead
- SSH key allows you to establish a secure connection between your computer and Gitlab
+%p.slead
+ SSH key allows you to establish a secure connection between your computer and GitLab
-%table#keys-table.admin-table
+%table#keys-table
%thead
%tr
%th Name
@@ -15,7 +15,7 @@
%th
- @keys.each do |key|
= render(partial: 'show', locals: {key: key})
- - if @keys.blank?
+ - if @keys.blank?
%tr
%td{colspan: 3}
%h3.nothing_here_message There are no SSH keys with access to your account.
diff --git a/app/views/keys/show.html.haml b/app/views/keys/show.html.haml
index ffd52b96..a8cba6c8 100644
--- a/app/views/keys/show.html.haml
+++ b/app/views/keys/show.html.haml
@@ -10,5 +10,5 @@
%hr
%pre= @key.key
-.actions
+.right
= link_to 'Remove', @key, confirm: 'Are you sure?', method: :delete, class: "btn danger delete-key"
diff --git a/app/views/labels/_label.html.haml b/app/views/labels/_label.html.haml
new file mode 100644
index 00000000..8a465a9e
--- /dev/null
+++ b/app/views/labels/_label.html.haml
@@ -0,0 +1,9 @@
+%li.wll
+ %strong
+ %i.icon-tag
+ = label.name
+ .right
+ = link_to project_issues_path(label_name: label.name) do
+ %strong
+ = pluralize(label.count, 'issue')
+ = "»"
diff --git a/app/views/labels/index.html.haml b/app/views/labels/index.html.haml
new file mode 100644
index 00000000..4e41d375
--- /dev/null
+++ b/app/views/labels/index.html.haml
@@ -0,0 +1,14 @@
+= render "issues/head"
+
+%h3.page_title
+ Labels
+%br
+%div.ui-box
+ %ul.unstyled.labels-table
+ - @labels.each do |label|
+ = render 'label', label: label
+
+ - unless @labels.present?
+ %li
+ %h3.nothing_here_message Nothing to show here
+
diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml
index d6247d36..f5e423a5 100644
--- a/app/views/layouts/_head_panel.html.haml
+++ b/app/views/layouts/_head_panel.html.haml
@@ -34,12 +34,4 @@
source: #{raw search_autocomplete_source},
select: function(event, ui) { location.href = ui.item.url }
});
-
- $(document).keypress(function(e) {
- if($(e.target).is(":input")) return;
- switch(e.which) {
- case 115: focusSearch();
- e.preventDefault();
- }
- });
});
diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml
index a1938df4..7b79897b 100644
--- a/app/views/layouts/notify.html.haml
+++ b/app/views/layouts/notify.html.haml
@@ -2,7 +2,7 @@
%head
%meta{content: "text/html; charset=utf-8", "http-equiv" => "Content-Type"}
%title
- gitlabhq
+ GitLab
:css
.header h1 {color: #BBBBBB !important; font: bold 32px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 40px;}
.header p {color: #c6c6c6; font: normal 12px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 18px;}
@@ -21,7 +21,7 @@
\Â
%td{align: "left", style: "padding: 18px 0 10px;", width: "580"}
%h1{style: "color: #BBBBBB; font: normal 32px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 40px;"}
- gitlab
+ GITLAB
- if @project
| #{@project.name}
%table{align: "center", bgcolor: "#fff", border: "0", cellpadding: "0", cellspacing: "0", style: "font-family: Helvetica, Arial, sans-serif; background: #fff;", width: "600"}
diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml
index b624415d..62c8db5b 100644
--- a/app/views/layouts/profile.html.haml
+++ b/app/views/layouts/profile.html.haml
@@ -9,20 +9,20 @@
%li.home{class: tab_class(:profile)}
= link_to "Profile", profile_path
- %li{class: tab_class(:password)}
- = link_to "Password", profile_password_path
+ %li{class: tab_class(:account)}
+ = link_to "Account", profile_account_path
%li{class: tab_class(:ssh_keys)}
= link_to keys_path do
SSH Keys
%span.count= current_user.keys.count
- %li{class: tab_class(:token)}
- = link_to "Token", profile_token_path
-
%li{class: tab_class(:design)}
= link_to "Design", profile_design_path
+ %li{class: tab_class(:history)}
+ = link_to "History", profile_history_path
+
.content
= yield
diff --git a/app/views/merge_requests/_form.html.haml b/app/views/merge_requests/_form.html.haml
index b6c12397..96692c0f 100644
--- a/app/views/merge_requests/_form.html.haml
+++ b/app/views/merge_requests/_form.html.haml
@@ -9,27 +9,27 @@
%br
.row
- .span6
+ .span5
.mr_branch_box
%h5 From (Head Branch)
.body
.padded
= f.label :source_branch, "From", class: "control-label"
.controls
- = f.select(:source_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, style: "width:250px")
- .bottom_commit
- .mr_source_commit
+ = f.select(:source_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span3'})
+ .mr_source_commit
- .span6
+ .span2
+ %center= image_tag "merge.png", class: 'mr_direction_tip'
+ .span5
.mr_branch_box
%h5 To (Base Branch)
.body
.padded
= f.label :target_branch, "To", class: "control-label"
.controls
- = f.select(:target_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, style: "width:250px")
- .bottom_commit
- .mr_target_commit
+ = f.select(:target_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span3'})
+ .mr_target_commit
%h4.cdark 2. Fill info
@@ -43,30 +43,25 @@
= f.label :assignee_id do
%i.icon-user
Assign to
- .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, style: "width:250px")
+ .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'})
.control-group
.form-actions
- = f.submit 'Save', class: "btn-primary btn"
+ = f.submit 'Save', class: "btn save-btn"
- if @merge_request.new_record?
- = link_to project_merge_requests_path(@project), class: "btn" do
+ = link_to project_merge_requests_path(@project), class: "btn cancel-btn" do
Cancel
- else
- = link_to project_merge_request_path(@project, @merge_request), class: "btn" do
+ = link_to project_merge_request_path(@project, @merge_request), class: "btn cancel-btn" do
Cancel
-
-
:javascript
$(function(){
- $('select#merge_request_assignee_id').chosen();
- $('select#merge_request_source_branch').chosen();
- $('select#merge_request_target_branch').chosen();
+ disableButtonIfEmptyField("#merge_request_title", ".save-btn");
var source_branch = $("#merge_request_source_branch");
var target_branch = $("#merge_request_target_branch");
-
$.get("#{branch_from_project_merge_requests_path(@project)}", {ref: source_branch.val() });
$.get("#{branch_to_project_merge_requests_path(@project)}", {ref: target_branch.val() });
@@ -78,4 +73,3 @@
$.get("#{branch_to_project_merge_requests_path(@project)}", {ref: $(this).val() });
});
});
-
diff --git a/app/views/merge_requests/_merge_request.html.haml b/app/views/merge_requests/_merge_request.html.haml
index 74996090..9d94d670 100644
--- a/app/views/merge_requests/_merge_request.html.haml
+++ b/app/views/merge_requests/_merge_request.html.haml
@@ -23,5 +23,6 @@
authored by #{merge_request.author_name}
= time_ago_in_words(merge_request.created_at)
ago
- - if merge_request.upvotes > 0
- %span.badge.badge-success= "+#{merge_request.upvotes}"
+
+ - if merge_request.votes_count > 0
+ = render 'votes/votes_inline', votable: merge_request
diff --git a/app/views/merge_requests/_show.html.haml b/app/views/merge_requests/_show.html.haml
index f1b3fa9f..f1d0c8aa 100644
--- a/app/views/merge_requests/_show.html.haml
+++ b/app/views/merge_requests/_show.html.haml
@@ -15,8 +15,8 @@
%i.icon-list-alt
Diff
-.merge_request_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" }
- = render("notes/notes", tid: @merge_request.id, tt: "merge_request")
+.merge_request_notes.voting_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" }
+ = render("notes/notes_with_form", tid: @merge_request.id, tt: "merge_request")
.merge-request-diffs
= render "merge_requests/show/diffs" if @diffs
.status
diff --git a/app/views/merge_requests/diffs.html.haml b/app/views/merge_requests/diffs.html.haml
index 176b19bc..a755491c 100644
--- a/app/views/merge_requests/diffs.html.haml
+++ b/app/views/merge_requests/diffs.html.haml
@@ -1,2 +1,6 @@
= render "show"
+:javascript
+ $(function(){
+ PerLineNotes.init();
+ });
diff --git a/app/views/merge_requests/diffs.js.haml b/app/views/merge_requests/diffs.js.haml
index b147e5be..98539985 100644
--- a/app/views/merge_requests/diffs.js.haml
+++ b/app/views/merge_requests/diffs.js.haml
@@ -1,4 +1,7 @@
:plain
$(".merge-request-diffs").html("#{escape_javascript(render(partial: "merge_requests/show/diffs"))}");
+ $(function(){
+ PerLineNotes.init();
+ });
diff --git a/app/views/merge_requests/index.html.haml b/app/views/merge_requests/index.html.haml
index 4ad6e5c1..bbf35dc7 100644
--- a/app/views/merge_requests/index.html.haml
+++ b/app/views/merge_requests/index.html.haml
@@ -1,7 +1,7 @@
%h3.page_title
Merge Requests
- if can? current_user, :write_issue, @project
- = link_to new_project_merge_request_path(@project), class: "right btn small", title: "New Merge Request" do
+ = link_to new_project_merge_request_path(@project), class: "right btn", title: "New Merge Request" do
New Merge Request
%br
@@ -10,17 +10,17 @@
.ui-box
.title
%ul.nav.nav-pills
- %li{class: ("active" if (params[:f] == "0" || !params[:f]))}
- = link_to project_merge_requests_path(@project, f: 0) do
+ %li{class: ("active" if (params[:f] == 'open' || !params[:f]))}
+ = link_to project_merge_requests_path(@project, f: 'open') do
Open
- %li{class: ("active" if params[:f] == "2")}
- = link_to project_merge_requests_path(@project, f: 2) do
+ %li{class: ("active" if params[:f] == "closed")}
+ = link_to project_merge_requests_path(@project, f: "closed") do
Closed
- %li{class: ("active" if params[:f] == "3")}
- = link_to project_merge_requests_path(@project, f: 3) do
+ %li{class: ("active" if params[:f] == 'assigned-to-me')}
+ = link_to project_merge_requests_path(@project, f: 'assigned-to-me') do
To Me
- %li{class: ("active" if params[:f] == "1")}
- = link_to project_merge_requests_path(@project, f: 1) do
+ %li{class: ("active" if params[:f] == 'all')}
+ = link_to project_merge_requests_path(@project, f: 'all') do
All
%ul.unstyled
diff --git a/app/views/merge_requests/show.js.haml b/app/views/merge_requests/show.js.haml
index 7a27b166..f44ccbb5 100644
--- a/app/views/merge_requests/show.js.haml
+++ b/app/views/merge_requests/show.js.haml
@@ -1,2 +1,2 @@
:plain
- $(".merge-request-notes").html("#{escape_javascript(render("notes/notes", tid: @merge_request.id, tt: "merge_request"))}");
+ $(".merge-request-notes").html("#{escape_javascript(render notes/notes_with_form", tid: @merge_request.id, tt: "merge_request")}");
diff --git a/app/views/merge_requests/show/_mr_box.html.haml b/app/views/merge_requests/show/_mr_box.html.haml
index 81ab83f3..89c3110b 100644
--- a/app/views/merge_requests/show/_mr_box.html.haml
+++ b/app/views/merge_requests/show/_mr_box.html.haml
@@ -5,7 +5,7 @@
.alert-message.error.status_info Closed
- else
.alert-message.success.status_info Open
- = gfm @merge_request.title
+ = gfm escape_once(@merge_request.title)
.middle_box_content
%div
diff --git a/app/views/merge_requests/show/_mr_title.html.haml b/app/views/merge_requests/show/_mr_title.html.haml
index 31fa0779..8708469c 100644
--- a/app/views/merge_requests/show/_mr_title.html.haml
+++ b/app/views/merge_requests/show/_mr_title.html.haml
@@ -1,9 +1,9 @@
%h3.page_title
= "Merge Request ##{@merge_request.id}:"
- %span.pretty_label.branch= @merge_request.source_branch
+ %span.label_branch= @merge_request.source_branch
→
- %span.pretty_label.branch= @merge_request.target_branch
+ %span.label_branch= @merge_request.target_branch
%span.right
- if @merge_request.merged?
@@ -23,10 +23,8 @@
%i.icon-edit
Edit
- %br
- - if @merge_request.upvotes > 0
- .upvotes#upvotes= "+#{pluralize @merge_request.upvotes, 'upvote'}"
-
+.right
+ .span3#votes= render 'votes/votes_block', votable: @merge_request
.back_link
= link_to project_merge_requests_path(@project) do
diff --git a/app/views/milestones/_form.html.haml b/app/views/milestones/_form.html.haml
index 1cd08ac3..194eac77 100644
--- a/app/views/milestones/_form.html.haml
+++ b/app/views/milestones/_form.html.haml
@@ -22,7 +22,7 @@
= f.label :description, "Description", class: "control-label"
.controls
= f.text_area :description, maxlength: 2000, class: "input-xlarge", rows: 10
- %p.hint Markdown is enabled.
+ %p.hint Milestones are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
.span6
.control-group
= f.label :due_date, "Due Date", class: "control-label"
@@ -32,20 +32,16 @@
.form-actions
- if @milestone.new_record?
- = f.submit 'Create milestone', class: "primary btn"
+ = f.submit 'Create milestone', class: "save-btn btn"
+ = link_to "Cancel", project_milestones_path(@project), class: "btn cancel-btn"
-else
- = f.submit 'Save changes', class: "primary btn"
+ = f.submit 'Save changes', class: "save-btn btn"
+ = link_to "Cancel", project_milestone_path(@project, @milestone), class: "btn cancel-btn"
- - if request.xhr?
- = link_to "Cancel", "#back", onclick: "backToIssues();", class: "btn"
- - else
- - if @milestone.new_record?
- = link_to "Cancel", project_milestones_path(@project), class: "btn"
- - else
- = link_to "Cancel", project_milestone_path(@project, @milestone), class: "btn"
:javascript
$(function() {
+ disableButtonIfEmptyField("#milestone_title", ".save-btn");
$( ".datepicker" ).datepicker({
dateFormat: "yy-mm-dd",
onSelect: function(dateText, inst) { $("#milestone_due_date").val(dateText) }
diff --git a/app/views/milestones/edit.html.haml b/app/views/milestones/edit.html.haml
index af975a84..b1bc3ba0 100644
--- a/app/views/milestones/edit.html.haml
+++ b/app/views/milestones/edit.html.haml
@@ -1,7 +1 @@
= render "form"
-
-:javascript
- $(function(){
- $('select#issue_assignee_id').chosen();
- });
-
diff --git a/app/views/milestones/index.html.haml b/app/views/milestones/index.html.haml
index ecb008dc..c5333b08 100644
--- a/app/views/milestones/index.html.haml
+++ b/app/views/milestones/index.html.haml
@@ -8,11 +8,11 @@
%div.ui-box
.title
%ul.nav.nav-pills
- %li{class: ("active" if (params[:f] == "0" || !params[:f]))}
- = link_to project_milestones_path(@project, f: 0) do
+ %li{class: ("active" if (params[:f] == "active" || !params[:f]))}
+ = link_to project_milestones_path(@project, f: "active") do
Active
- %li{class: ("active" if params[:f] == "1")}
- = link_to project_milestones_path(@project, f: 1) do
+ %li{class: ("active" if params[:f] == "all")}
+ = link_to project_milestones_path(@project, f: "all") do
All
%ul.unstyled
diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml
index b7da7b66..ba71ead7 100644
--- a/app/views/milestones/show.html.haml
+++ b/app/views/milestones/show.html.haml
@@ -21,7 +21,7 @@
.alert-message.error.status_info Closed
- else
.alert-message.success.status_info Open
- = gfm @milestone.title
+ = gfm escape_once(@milestone.title)
%small.right= @milestone.expires_at
.middle_box_content
@@ -42,7 +42,7 @@
.row
.span6
- %table.admin-table
+ %table
%thead
%th Open Issues
- @issues.each do |issue|
@@ -56,7 +56,7 @@
= paginate @issues, theme: "gitlab"
.span6
- %table.admin-table
+ %table
%thead
%th Participants
- @users.each do |user|
diff --git a/app/views/notes/_common_form.html.haml b/app/views/notes/_common_form.html.haml
new file mode 100644
index 00000000..fc6e3c7e
--- /dev/null
+++ b/app/views/notes/_common_form.html.haml
@@ -0,0 +1,39 @@
+.note-form-holder
+ = form_for [@project, @note], remote: "true", multipart: true do |f|
+ %h3.page_title Leave a comment
+ -if @note.errors.any?
+ .alert-message.block-message.error
+ - @note.errors.full_messages.each do |msg|
+ %div= msg
+
+ = f.hidden_field :noteable_id
+ = f.hidden_field :noteable_type
+ = f.text_area :note, size: 255, class: 'note-text'
+ #preview-note.preview_note.hide
+ .hint
+ .right Comments are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
+ .clearfix
+
+ .row.note_advanced_opts
+ .span3
+ = f.submit 'Add Comment', class: "btn success submit_note grouped", id: "submit_note"
+ = link_to 'Preview', preview_project_notes_path(@project), class: 'btn grouped', id: 'preview-link'
+ .span4.notify_opts
+ %h6.left Notify via email:
+ = label_tag :notify do
+ = check_box_tag :notify, 1, @note.noteable_type != "Commit"
+ %span Project team
+
+ - if @note.notify_only_author?(current_user)
+ = label_tag :notify_author do
+ = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"
+ %span Commit author
+ .span5.attachments
+ %h6.left Attachment:
+ %span.file_name File name...
+
+ .input.input_file
+ %a.file_upload.btn.small Upload File
+ = f.file_field :attachment, class: "input-file"
+ %span.hint Any file less than 10 MB
+
diff --git a/app/views/notes/_create_common.js.haml b/app/views/notes/_create_common.js.haml
deleted file mode 100644
index e9538902..00000000
--- a/app/views/notes/_create_common.js.haml
+++ /dev/null
@@ -1,11 +0,0 @@
-- if note.valid?
- :plain
- $("#new_note .error").remove();
- $('#new_note textarea').val("");
- $('#preview-link').text('Preview');
- $('#preview-note').hide(); $('#note_note').show();
- NoteList.prepend(#{note.id}, "#{escape_javascript(render partial: "notes/show", locals: {note: note})}");
-- else
- :plain
- $("#new_note").replaceWith("#{escape_javascript(render('form'))}");
-
diff --git a/app/views/notes/_create_common_note.js.haml b/app/views/notes/_create_common_note.js.haml
new file mode 100644
index 00000000..bbebc247
--- /dev/null
+++ b/app/views/notes/_create_common_note.js.haml
@@ -0,0 +1,13 @@
+- if note.valid?
+ :plain
+ $(".note-form-holder .error").remove();
+ $('.note-form-holder textarea').val("");
+ $('.note-form-holder #preview-link').text('Preview');
+ $('.note-form-holder #preview-note').hide();
+ $('.note-form-holder').show();
+ NoteList.appendNewNote(#{note.id}, "#{escape_javascript(render "notes/note", note: note)}");
+
+- else
+ :plain
+ $(".note-form-holder").replaceWith("#{escape_javascript(render 'form')}");
+
diff --git a/app/views/notes/_create_line.js.haml b/app/views/notes/_create_line.js.haml
deleted file mode 100644
index 13809bec..00000000
--- a/app/views/notes/_create_line.js.haml
+++ /dev/null
@@ -1,8 +0,0 @@
-- if note.valid?
- :plain
- $(".per_line_form").hide();
- $('#new_note textarea').val("");
- $("a.line_note_reply_link[line_code='#{note.line_code}']").closest("tr").remove();
- var trEl = $(".#{note.line_code}").parent();
- trEl.after("#{escape_javascript(render partial: "notes/per_line_show", locals: {note: note})}");
- trEl.after("#{escape_javascript(render partial: "notes/reply_button", locals: {line_code: note.line_code})}");
diff --git a/app/views/notes/_create_per_line_note.js.haml b/app/views/notes/_create_per_line_note.js.haml
new file mode 100644
index 00000000..180960e3
--- /dev/null
+++ b/app/views/notes/_create_per_line_note.js.haml
@@ -0,0 +1,19 @@
+- if note.valid?
+ :plain
+ // hide and reset the form
+ $(".per_line_form").hide();
+ $('.line-note-form-holder textarea').val("");
+
+ // find the reply button for this line
+ // (might not be there if this is the first note)
+ var trRpl = $("a.line_note_reply_link[data-line-code='#{note.line_code}']").closest("tr");
+ if (trRpl.size() == 0) {
+ // find the commented line ...
+ var trEl = $(".#{note.line_code}").parent();
+ // ... and insert the note and the reply button after it
+ trEl.after("#{escape_javascript(render "notes/per_line_reply_button", line_code: note.line_code)}");
+ trEl.after("#{escape_javascript(render "notes/per_line_note", note: note)}");
+ } else {
+ // instert new note before reply button
+ trRpl.before("#{escape_javascript(render "notes/per_line_note", note: note)}");
+ }
diff --git a/app/views/notes/_form.html.haml b/app/views/notes/_form.html.haml
deleted file mode 100644
index dac026bd..00000000
--- a/app/views/notes/_form.html.haml
+++ /dev/null
@@ -1,38 +0,0 @@
-= form_for [@project, @note], remote: "true", multipart: true do |f|
- %h3.page_title Leave a comment
- -if @note.errors.any?
- .alert-message.block-message.error
- - @note.errors.full_messages.each do |msg|
- %div= msg
-
- = f.hidden_field :noteable_id
- = f.hidden_field :noteable_type
- = f.text_area :note, size: 255
- #preview-note.well.hide
- %p.hint
- = link_to "Gitlab Markdown", help_markdown_path, target: '_blank'
- is enabled.
- = link_to 'Preview', preview_project_notes_path(@project), id: 'preview-link'
-
- .row.note_advanced_opts.hide
- .span2
- = f.submit 'Add Comment', class: "btn primary submit_note", id: "submit_note"
- .span4.notify_opts
- %h6.left Notify via email:
- = label_tag :notify do
- = check_box_tag :notify, 1, @note.noteable_type != "Commit"
- %span Project team
-
- - if @note.notify_only_author?(current_user)
- = label_tag :notify_author do
- = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"
- %span Commit author
- .span6.attachments
- %h6.left Attachment:
- %span.file_name File name...
-
- .input.input_file
- %a.file_upload.btn.small Upload File
- = f.file_field :attachment, class: "input-file"
- %span.hint Any file less than 10 MB
-
diff --git a/app/views/notes/_load.js.haml b/app/views/notes/_load.js.haml
deleted file mode 100644
index c16a699a..00000000
--- a/app/views/notes/_load.js.haml
+++ /dev/null
@@ -1,17 +0,0 @@
-- unless @notes.blank?
- - if params[:last_id]
- :plain
- NoteList.replace("#{escape_javascript(render(partial: 'notes/notes_list'))}");
-
- - elsif params[:first_id]
- :plain
- NoteList.append(#{@notes.last.id}, "#{escape_javascript(render(partial: 'notes/notes_list'))}");
-
- - else
- :plain
- NoteList.setContent(#{@notes.last.id}, #{@notes.first.id}, "#{escape_javascript(render(partial: 'notes/notes_list'))}");
-
-- else
- - if params[:first_id]
- :plain
- NoteList.append(#{params[:first_id]}, "");
diff --git a/app/views/notes/_show.html.haml b/app/views/notes/_note.html.haml
similarity index 73%
rename from app/views/notes/_show.html.haml
rename to app/views/notes/_note.html.haml
index 3412e4eb..5234e55d 100644
--- a/app/views/notes/_show.html.haml
+++ b/app/views/notes/_note.html.haml
@@ -1,4 +1,4 @@
-%li{id: dom_id(note), class: "note"}
+%li{id: dom_id(note), class: "note #{note_vote_class(note)}"}
= image_tag gravatar_icon(note.author.email), class: "avatar s32"
%div.note-author
%strong= note.author_name
@@ -6,8 +6,16 @@
%cite.cgray
= time_ago_in_words(note.updated_at)
ago
+ - if note.upvote?
+ %span.label.label-success
+ %i.icon-thumbs-up
+ \+1
+ - if note.downvote?
+ %span.label.label-error
+ %i.icon-thumbs-down
+ \-1
- if(note.author_id == current_user.id) || can?(current_user, :admin_note, @project)
- = link_to [@project, note], confirm: 'Are you sure?', method: :delete, remote: true, class: "cred delete-note btn very_small" do
+ = link_to [@project, note], confirm: 'Are you sure?', method: :delete, remote: true, class: "cred delete-note btn very_small" do
%i.icon-trash
Remove
diff --git a/app/views/notes/_notes.html.haml b/app/views/notes/_notes.html.haml
index e692e746..adb5dfcb 100644
--- a/app/views/notes/_notes.html.haml
+++ b/app/views/notes/_notes.html.haml
@@ -1,13 +1,4 @@
-- if can? current_user, :write_note, @project
- = render "notes/form"
-.clear
-%hr
-%ul#new_notes_list
-%ul#notes-list
-.status
+- @notes.each do |note|
+ - next unless note.author
+ = render "note", note: note
-
-:javascript
- $(function(){
- NoteList.init("#{tid}", "#{tt}", "#{project_notes_path(@project)}");
- });
diff --git a/app/views/notes/_notes_list.html.haml b/app/views/notes/_notes_list.html.haml
deleted file mode 100644
index 5673988d..00000000
--- a/app/views/notes/_notes_list.html.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-- @notes.each do |note|
- - next unless note.author
- = render partial: "notes/show", locals: {note: note}
-
diff --git a/app/views/notes/_notes_with_form.html.haml b/app/views/notes/_notes_with_form.html.haml
new file mode 100644
index 00000000..53716c1d
--- /dev/null
+++ b/app/views/notes/_notes_with_form.html.haml
@@ -0,0 +1,11 @@
+%ul#notes-list
+%ul#new-notes-list
+.notes-status
+
+- if can? current_user, :write_note, @project
+ = render "notes/common_form"
+
+:javascript
+ $(function(){
+ NoteList.init("#{tid}", "#{tt}", "#{project_notes_path(@project)}");
+ });
diff --git a/app/views/notes/_per_line_form.html.haml b/app/views/notes/_per_line_form.html.haml
index afb0b30d..8e31b59e 100644
--- a/app/views/notes/_per_line_form.html.haml
+++ b/app/views/notes/_per_line_form.html.haml
@@ -1,33 +1,34 @@
%table{style: "display:none;"}
%tr.per_line_form
%td{colspan: 3 }
- = form_for [@project, @note], remote: "true", multipart: true do |f|
- %h3.page_title Leave a note
- %div.span10
- -if @note.errors.any?
- .alert-message.block-message.error
- - @note.errors.full_messages.each do |msg|
- %div= msg
+ .line-note-form-holder
+ = form_for [@project, @note], remote: "true", multipart: true do |f|
+ %h3.page_title Leave a note
+ %div.span10
+ -if @note.errors.any?
+ .alert-message.block-message.error
+ - @note.errors.full_messages.each do |msg|
+ %div= msg
- = f.hidden_field :noteable_id
- = f.hidden_field :noteable_type
- = f.hidden_field :line_code
- = f.text_area :note, size: 255
- .note_actions
- .buttons
- = f.submit 'Add note', class: "btn primary submit_note", id: "submit_note"
- = link_to "Cancel", "#", class: "btn hide-button"
- .options
- %h6.left Notify via email:
- .labels
- = label_tag :notify do
- = check_box_tag :notify, 1, @note.noteable_type != "Commit"
- %span Project team
+ = f.hidden_field :noteable_id
+ = f.hidden_field :noteable_type
+ = f.hidden_field :line_code
+ = f.text_area :note, size: 255, class: 'line-note-text'
+ .note_actions
+ .buttons
+ = f.submit 'Add note', class: "btn save-btn submit_note submit_inline_note", id: "submit_note"
+ = link_to "Cancel", "#", class: "btn hide-button"
+ .options
+ %h6.left Notify via email:
+ .labels
+ = label_tag :notify do
+ = check_box_tag :notify, 1, @note.noteable_type != "Commit"
+ %span Project team
- - if @note.notify_only_author?(current_user)
- = label_tag :notify_author do
- = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"
- %span Commit author
+ - if @note.notify_only_author?(current_user)
+ = label_tag :notify_author do
+ = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"
+ %span Commit author
:javascript
$(function(){
diff --git a/app/views/notes/_per_line_note.html.haml b/app/views/notes/_per_line_note.html.haml
new file mode 100644
index 00000000..28bcd6e0
--- /dev/null
+++ b/app/views/notes/_per_line_note.html.haml
@@ -0,0 +1,5 @@
+%tr.line_notes_row
+ %td{colspan: 3}
+ %ul
+ = render "notes/note", note: note
+
diff --git a/app/views/notes/_per_line_note_link.html.haml b/app/views/notes/_per_line_note_link.html.haml
new file mode 100644
index 00000000..72b59a59
--- /dev/null
+++ b/app/views/notes/_per_line_note_link.html.haml
@@ -0,0 +1 @@
+= link_to "", "#", class: "line_note_link", data: { line_code: line_code }, title: "Add note for this line"
diff --git a/app/views/notes/_per_line_notes_with_reply.html.haml b/app/views/notes/_per_line_notes_with_reply.html.haml
new file mode 100644
index 00000000..1bcfc41f
--- /dev/null
+++ b/app/views/notes/_per_line_notes_with_reply.html.haml
@@ -0,0 +1,3 @@
+- notes.each do |note|
+ = render "notes/per_line_note", note: note
+= render "notes/per_line_reply_button", line_code: notes.first.line_code
diff --git a/app/views/notes/_per_line_reply_button.html.haml b/app/views/notes/_per_line_reply_button.html.haml
new file mode 100644
index 00000000..42c737c7
--- /dev/null
+++ b/app/views/notes/_per_line_reply_button.html.haml
@@ -0,0 +1,4 @@
+%tr.line_notes_row.reply
+ %td{colspan: 3}
+ %i.icon-comment
+ = link_to "Reply", "#", class: "line_note_reply_link", data: { line_code: line_code }, title: "Add note for this line"
diff --git a/app/views/notes/_per_line_show.html.haml b/app/views/notes/_per_line_show.html.haml
deleted file mode 100644
index cf1769c0..00000000
--- a/app/views/notes/_per_line_show.html.haml
+++ /dev/null
@@ -1,5 +0,0 @@
-%tr.line_notes_row
- %td{colspan: 3}
- %ul
- = render partial: "notes/show", locals: {note: note}
-
diff --git a/app/views/notes/_reply_button.html.haml b/app/views/notes/_reply_button.html.haml
deleted file mode 100644
index c981fb9f..00000000
--- a/app/views/notes/_reply_button.html.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-%tr.line_notes_row.reply
- %td{colspan: 3}
- %i.icon-comment
- = link_to "Reply", "#", class: "line_note_reply_link", "line_code" => line_code, title: "Add note for this line"
diff --git a/app/views/notes/_reversed_notes_with_form.html.haml b/app/views/notes/_reversed_notes_with_form.html.haml
new file mode 100644
index 00000000..24d59924
--- /dev/null
+++ b/app/views/notes/_reversed_notes_with_form.html.haml
@@ -0,0 +1,11 @@
+- if can? current_user, :write_note, @project
+ = render "notes/common_form"
+
+%ul.reversed#new-notes-list
+%ul.reversed#notes-list
+.notes-status
+
+:javascript
+ $(function(){
+ NoteList.init("#{tid}", "#{tt}", "#{project_notes_path(@project)}");
+ });
diff --git a/app/views/notes/create.js.haml b/app/views/notes/create.js.haml
index 8f631f38..03866591 100644
--- a/app/views/notes/create.js.haml
+++ b/app/views/notes/create.js.haml
@@ -1,7 +1,7 @@
- if @note.line_code
- = render "create_line", note: @note
+ = render "create_per_line_note", note: @note
- else
- = render "create_common", note: @note
+ = render "create_common_note", note: @note
-# Enable submit button
:plain
diff --git a/app/views/notes/index.js.haml b/app/views/notes/index.js.haml
index ee31c0b8..3814dbd4 100644
--- a/app/views/notes/index.js.haml
+++ b/app/views/notes/index.js.haml
@@ -1 +1,17 @@
-= render "notes/load"
+- unless @notes.blank?
+ - if loading_more_notes?
+ :plain
+ NoteList.appendMoreNotes(#{@notes.last.id}, "#{escape_javascript(render 'notes/notes')}");
+
+ - elsif loading_new_notes?
+ :plain
+ NoteList.replaceNewNotes("#{escape_javascript(render 'notes/notes')}");
+
+ - else
+ :plain
+ NoteList.setContent(#{@notes.first.id}, #{@notes.last.id}, "#{escape_javascript(render 'notes/notes')}");
+
+- else
+ - if loading_more_notes?
+ :plain
+ NoteList.finishedLoadingMore();
diff --git a/app/views/notify/issue_status_changed_email.html.haml b/app/views/notify/issue_status_changed_email.html.haml
new file mode 100644
index 00000000..59130f79
--- /dev/null
+++ b/app/views/notify/issue_status_changed_email.html.haml
@@ -0,0 +1,16 @@
+%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"}
+ %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"}
+ %tr
+ %td{style: "font-size: 1px; line-height: 1px;", width: "21"}
+ %td{align: "left", style: "padding: 20px 0 0;"}
+ %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
+ = "Issue was #{@issue_status} by #{@updated_by.name}"
+ %td{style: "font-size: 1px; line-height: 1px;", width: "21"}
+ %tr
+ %td{style: "font-size: 1px; line-height: 1px;", width: "21"}
+ %td{align: "left", style: "padding: 20px 0 0;"}
+ %h2{style: "color:#646464 !important; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
+ = "Issue ##{@issue.id}"
+ = link_to_gfm truncate(@issue.title, length: 45), project_issue_url(@issue.project, @issue), title: @issue.title
+ %br
+
diff --git a/app/views/notify/new_user_email.html.haml b/app/views/notify/new_user_email.html.haml
index d96afc92..93bf7c50 100644
--- a/app/views/notify/new_user_email.html.haml
+++ b/app/views/notify/new_user_email.html.haml
@@ -6,7 +6,7 @@
%h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
Hi #{@user['name']}!
%p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
- Administrator created account for you. Now you are a member of company gitlab application.
+ Administrator created account for you. Now you are a member of company GitLab application.
%td{style: "font-size: 1px; line-height: 1px;", width: "21"}
%tr
%td{style: "font-size: 1px; line-height: 1px;", width: "21"}
diff --git a/app/views/notify/project_access_granted_email.html.haml b/app/views/notify/project_access_granted_email.html.haml
new file mode 100644
index 00000000..154c2aaa
--- /dev/null
+++ b/app/views/notify/project_access_granted_email.html.haml
@@ -0,0 +1,14 @@
+%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"}
+ %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"}
+ %tr
+ %td{style: "font-size: 1px; line-height: 1px;", width: "21"}
+ %td{align: "left", style: "padding: 20px 0 0;"}
+ %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
+ = "You got granted #{@users_project.project_access_human} access to project"
+ %td{style: "font-size: 1px; line-height: 1px;", width: "21"}
+ %tr
+ %td{style: "font-size: 1px; line-height: 1px;", width: "21"}
+ %td{align: "left", style: "padding: 20px 0 0;"}
+ %h2{style: "color:#646464 !important; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
+ = link_to_gfm truncate(@project.name, length: 45), project_url(@project), title: @project.name
+ %br
diff --git a/app/views/profile/account.html.haml b/app/views/profile/account.html.haml
new file mode 100644
index 00000000..6707a8ff
--- /dev/null
+++ b/app/views/profile/account.html.haml
@@ -0,0 +1,57 @@
+- if Gitlab.config.omniauth_enabled?
+ %fieldset
+ %legend
+ %h3.page_title Social Accounts
+ .oauth_select_holder
+ %p.hint Tip: Click on icon to activate sigin with one of the following services
+ - User.omniauth_providers.each do |provider|
+ %span{class: oauth_active_class(provider) }
+ = link_to authbutton(provider, 32), omniauth_authorize_path(User, provider)
+
+
+%fieldset
+ %legend
+ %h3.page_title
+ Private token
+ %span.cred.right
+ keep it in secret!
+ .padded
+ = form_for @user, url: profile_reset_private_token_path, method: :put do |f|
+ .data
+ %p.slead
+ Private token used to access application resources without authentication.
+ %br
+ It can be used for atom feed or API
+ %p.cgray
+ - if current_user.private_token
+ = text_field_tag "token", current_user.private_token, class: "xxlarge large_text"
+ = f.submit 'Reset', confirm: "Are you sure?", class: "btn primary btn-build-token"
+ - else
+ %span You don`t have one yet. Click generate to fix it.
+ = f.submit 'Generate', class: "btn success btn-build-token"
+
+%fieldset
+ %legend
+ %h3.page_title Password
+ = form_for @user, url: profile_password_path, method: :put do |f|
+ .padded
+ %p.slead After successful password update you will be redirected to login page where you should login with new password
+ -if @user.errors.any?
+ .alert-message.block-message.error
+ %ul
+ - @user.errors.full_messages.each do |msg|
+ %li= msg
+
+ .clearfix
+ = f.label :password
+ .input= f.password_field :password
+ .clearfix
+ = f.label :password_confirmation
+ .input= f.password_field :password_confirmation
+ .actions
+ = f.submit 'Save', class: "btn save-btn"
+
+
+
+
+
diff --git a/app/views/profile/history.html.haml b/app/views/profile/history.html.haml
new file mode 100644
index 00000000..aa7006c5
--- /dev/null
+++ b/app/views/profile/history.html.haml
@@ -0,0 +1,5 @@
+.profile_history
+ = render @events
+%hr
+= paginate @events, theme: "gitlab"
+
diff --git a/app/views/profile/password.html.haml b/app/views/profile/password.html.haml
deleted file mode 100644
index 257dacb1..00000000
--- a/app/views/profile/password.html.haml
+++ /dev/null
@@ -1,19 +0,0 @@
-%h3.page_title Password
-%hr
-= form_for @user, url: profile_password_path, method: :put do |f|
- .data
- %p.slead After successful password update you will be redirected to login page where you should login with new password
- -if @user.errors.any?
- .alert-message.block-message.error
- %ul
- - @user.errors.full_messages.each do |msg|
- %li= msg
-
- .clearfix
- = f.label :password
- .input= f.password_field :password
- .clearfix
- = f.label :password_confirmation
- .input= f.password_field :password_confirmation
- .actions
- = f.submit 'Save', class: "btn primary"
diff --git a/app/views/profile/show.html.haml b/app/views/profile/show.html.haml
index 95cce2bb..7b625291 100644
--- a/app/views/profile/show.html.haml
+++ b/app/views/profile/show.html.haml
@@ -6,7 +6,6 @@
%small
= @user.email
-
%hr
= form_for @user, url: profile_update_path, method: :put, html: { class: "edit_user form-horizontal" } do |f|
@@ -28,7 +27,23 @@
= f.text_field :email, class: "input-xlarge"
%span.help-block We also use email for avatar detection.
- %hr
+ .span5.right
+ %div.tips
+ %h6 Tips:
+ %ul
+ -unless Gitlab.config.disable_gravatar?
+ %li
+ %p.hint You can change your avatar at #{link_to "gravatar.com", "http://gravatar.com"}
+
+ - if Gitlab.config.omniauth_enabled? && @user.provider?
+ %li
+ %p.hint
+ You can login through #{@user.provider.titleize}!
+ = link_to "click here to change", profile_account_path
+
+ %hr
+ .row
+ .span7
.control-group
= f.label :skype, class: "control-label"
.controls= f.text_field :skype, class: "input-xlarge"
@@ -44,26 +59,24 @@
= f.text_area :bio, rows: 6, class: "input-xlarge", maxlength: 250
%span.help-block Tell us about yourself in fewer than 250 characters.
.span5.right
+ .ui-box.white
+ .ui-box-body
+ %h4
+ Personal projects:
+ %small.right
+ %span= current_user.my_own_projects.count
+ of
+ %span= current_user.projects_limit
+ .progress
+ .bar{style: "width: #{current_user.projects_limit_percent}%;"}
- %p.alert.alert-info
- %strong Tip:
- You can change your avatar at gravatar.com
+ .ui-box.white
+ .ui-box-body
+ %h4
+ SSH public keys:
+ %strong.right= link_to current_user.keys.count, keys_path
- %h4
- Personal projects:
- %small.right
- %span= current_user.my_own_projects.count
- of
- %span= current_user.projects_limit
- .progress
- .bar{style: "width: #{current_user.projects_limit_percent}%;"}
-
- %h4
- SSH public keys:
- %small.right
- %span= link_to current_user.keys.count, keys_path
-
- = link_to "Add Public Key", new_key_path, class: "btn small right"
+ = link_to "Add Public Key", new_key_path, class: "btn small"
.form-actions
- = f.submit 'Save', class: "btn-primary btn"
+ = f.submit 'Save', class: "btn save-btn"
diff --git a/app/views/profile/token.html.haml b/app/views/profile/token.html.haml
deleted file mode 100644
index 6c870c36..00000000
--- a/app/views/profile/token.html.haml
+++ /dev/null
@@ -1,23 +0,0 @@
-%h3.page_title
- Private token
- %span.cred.right
- keep it in secret!
-%hr
-= form_for @user, url: profile_reset_private_token_path, method: :put do |f|
- .data
- %p.slead
- Private token used to access application resources without authentication.
- %br
- It can be used for atom feed or API
- %p.cgray
- - if current_user.private_token
- = text_field_tag "token", current_user.private_token, class: "xxlarge large_text"
- - else
- You don`t have one yet. Click generate to fix it.
- .actions
- - if current_user.private_token
- = f.submit 'Reset', confirm: "Are you sure?", class: "btn"
- - else
- = f.submit 'Generate', class: "btn primary"
-
-
diff --git a/app/views/projects/_clone_panel.html.haml b/app/views/projects/_clone_panel.html.haml
new file mode 100644
index 00000000..20891610
--- /dev/null
+++ b/app/views/projects/_clone_panel.html.haml
@@ -0,0 +1,21 @@
+.project_clone_panel
+ .row
+ .span7
+ .form-horizontal
+ .input-prepend.project_clone_holder
+ %button{class: "btn small active", :"data-clone" => @project.ssh_url_to_repo} SSH
+ %button{class: "btn small", :"data-clone" => @project.http_url_to_repo} HTTP
+ = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select span5"
+ .span4.right
+ .right
+ - unless @project.empty_repo?
+ - if can? current_user, :download_code, @project
+ = link_to archive_project_repository_path(@project), class: "btn small grouped" do
+ %i.icon-download-alt
+ Download
+ - if @project.merge_requests_enabled && can?(current_user, :write_merge_request, @project)
+ = link_to new_project_merge_request_path(@project), title: "New Merge Request", class: "btn small grouped" do
+ Merge Request
+ - if @project.issues_enabled && can?(current_user, :write_issue, @project)
+ = link_to new_project_issue_path(@project), title: "New Issue", class: "btn small grouped" do
+ Issue
diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml
index ce66b2cf..8bdeda1c 100644
--- a/app/views/projects/_form.html.haml
+++ b/app/views/projects/_form.html.haml
@@ -10,9 +10,9 @@
.input
= f.text_field :name, placeholder: "Example Project", class: "xxlarge"
- %h5.page_title
- .alert.alert-info
- %h5 Advanced settings:
+ %hr
+ .adv_settings
+ %h6 Advanced settings:
.clearfix
= f.label :path do
Path
@@ -34,8 +34,9 @@
.input= f.select(:default_branch, @project.heads.map(&:name), {}, style: "width:210px;")
- unless @project.new_record?
- .alert.alert-info
- %h5 Features:
+ %hr
+ .adv_settings
+ %h6 Features:
.clearfix
= f.label :issues_enabled, "Issues"
@@ -56,7 +57,7 @@
%br
.actions
- = f.submit 'Save', class: "btn primary"
+ = f.submit 'Save', class: "btn save-btn"
= link_to 'Cancel', @project, class: "btn"
- unless @project.new_record?
.right
diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml
index 5104df83..e6d5e93f 100644
--- a/app/views/projects/_new_form.html.haml
+++ b/app/views/projects/_new_form.html.haml
@@ -7,11 +7,11 @@
Project name is
.input
= f.text_field :name, placeholder: "Example Project", class: "xxlarge"
- = f.submit 'Create project', class: "btn primary"
+ = f.submit 'Create project', class: "btn primary project-submit"
%hr
- .alert.alert-info
- %h5 Advanced settings:
+ %div.adv_settings
+ %h6 Advanced settings:
.clearfix
= f.label :path do
Git Clone
diff --git a/app/views/projects/_project_head.html.haml b/app/views/projects/_project_head.html.haml
index ba64ee7f..4f38bef8 100644
--- a/app/views/projects/_project_head.html.haml
+++ b/app/views/projects/_project_head.html.haml
@@ -3,8 +3,8 @@
= link_to project_path(@project), class: "activities-tab tab" do
%i.icon-home
Show
- %li{ class: " #{'active' if (controller.controller_name == "team_members") || current_page?(team_project_path(@project)) }" }
- = link_to team_project_path(@project), class: "team-tab tab" do
+ %li{ class: " #{'active' if (controller.controller_name == "team_members") || current_page?(project_team_index_path(@project)) }" }
+ = link_to project_team_index_path(@project), class: "team-tab tab" do
%i.icon-user
Team
%li{ class: "#{'active' if current_page?(files_project_path(@project)) }" }
diff --git a/app/views/projects/_refs.html.haml b/app/views/projects/_refs.html.haml
deleted file mode 100644
index 804b8523..00000000
--- a/app/views/projects/_refs.html.haml
+++ /dev/null
@@ -1,8 +0,0 @@
-= form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do
- = select_tag "ref", grouped_options_refs, onchange: "this.form.submit();", class: "project-refs-select"
- = hidden_field_tag :destination, destination
-
-:javascript
- $(function(){
- $('.project-refs-select').chosen();
- })
diff --git a/app/views/projects/_show.html.haml b/app/views/projects/_show.html.haml
deleted file mode 100644
index e8a5b00d..00000000
--- a/app/views/projects/_show.html.haml
+++ /dev/null
@@ -1,23 +0,0 @@
-%h5.title
- = @project.name
-%br
-%div
- %a.btn.info{href: tree_project_ref_path(@project, @project.root_ref)} Browse code
-
- %a.btn{href: project_commits_path(@project)} Commits
- %strong.right
- = link_to project_path(@project) do
- Switch to project →
-%br
-.alert-message.block-message.warning
- .input
- .input-prepend
- %span.add-on git clone
- = text_field_tag :project_clone, @project.url_to_repo, class: "xlarge one_click_select git_clone_url"
-
-= simple_format @project.description
-- unless @events.blank?
- %h4.middle_title Recent Activity
- .content_list= render @events
-
-
diff --git a/app/views/projects/_team.html.haml b/app/views/projects/_team.html.haml
deleted file mode 100644
index 175aea27..00000000
--- a/app/views/projects/_team.html.haml
+++ /dev/null
@@ -1,16 +0,0 @@
-%table.admin-table
- %thead
- %tr
- %th User
- %th Permissions
- %tbody
- - @project.users_projects.each do |up|
- = render(partial: 'team_members/show', locals: {member: up})
-
-
-:javascript
- $(function(){
- $('.repo-access-select, .project-access-select').live("change", function() {
- $(this.form).submit();
- });
- })
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 987d43ec..fdd537da 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -3,10 +3,10 @@
%h3.page_title Edit Project
%hr
= render "projects/form"
-%div.ajax_loader.hide
+%div.save-project-loader.hide
%center
- %div.padded= image_tag "ajax_loader.gif"
- %h3.prepend-top Saving project & repository. Please wait...
+ = image_tag "ajax_loader.gif"
+ %h3 Saving project. Please wait a few minutes
:javascript
$(function(){ new Projects(); });
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index 907d5ef4..d9a151fc 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -1,4 +1,6 @@
= render 'shared/no_ssh'
+= render 'clone_panel'
+
%div.git-empty
%h4 Git global setup:
%pre.dark
diff --git a/app/views/projects/files.html.haml b/app/views/projects/files.html.haml
index 68d51df0..ce8ba876 100644
--- a/app/views/projects/files.html.haml
+++ b/app/views/projects/files.html.haml
@@ -1,6 +1,11 @@
= render "project_head"
- unless @notes.empty?
- %table.zebra-striped.borders
+ %table
+ %thead
+ %tr
+ %th File name
+ %th
+
- @notes.each do |note|
%tr
%td
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 703e558a..933cb671 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -3,10 +3,10 @@
New Project
%hr
= render 'new_form'
-%div.ajax_loader.hide
+%div.save-project-loader.hide
%center
- %div.padded= image_tag "ajax_loader.gif"
- %h3.prepend-top Creating project & repository. Please wait a few minutes
+ = image_tag "ajax_loader.gif"
+ %h3 Creating project & repository. Please wait a few minutes
:javascript
$(function(){ new Projects(); });
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index ebd2c8e4..21459da2 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -1,37 +1,4 @@
= render "project_head"
-
-.entry
- .row
- .span7
- .form-horizontal
- .input-prepend.project_clone_holder
-
- %span.add-on git clone
- = link_to "SSH", "#", class: "btn small active", :"data-clone" => @project.ssh_url_to_repo
- = link_to "HTTP", "#", class: "btn small", :"data-clone" => @project.http_url_to_repo
- = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select span5"
- .span4.right
- .right
- - if can? current_user, :download_code, @project
- = link_to archive_project_repository_path(@project), class: "btn small grouped" do
- %i.icon-download-alt
- Download
- - if @project.merge_requests_enabled && can?(current_user, :write_merge_request, @project)
- = link_to new_project_merge_request_path(@project), title: "New Merge Request", class: "btn small grouped" do
- Merge Request
- - if @project.issues_enabled && can?(current_user, :write_issue, @project)
- = link_to new_project_issue_path(@project), title: "New Issue", class: "btn small grouped" do
- Issue
-
+= render 'clone_panel'
= render "events/event_last_push", event: @last_push
.content_list= render @events
-
-:javascript
- $(function(){
- var link_sel = ".project_clone_holder a";
- $(link_sel).bind("click", function() {
- $(link_sel).removeClass("active");
- $(this).addClass("active");
- $("#project_clone").val($(this).attr("data-clone"));
- })
- })
diff --git a/app/views/projects/wall.html.haml b/app/views/projects/wall.html.haml
index 97765d7a..591a8cd0 100644
--- a/app/views/projects/wall.html.haml
+++ b/app/views/projects/wall.html.haml
@@ -1,2 +1,2 @@
%div.wall_page
- = render "notes/notes", tid: nil, tt: "wall"
+ = render "notes/reversed_notes_with_form", tid: nil, tt: "wall"
diff --git a/app/views/protected_branches/index.html.haml b/app/views/protected_branches/index.html.haml
index 2b93b0a8..43884de1 100644
--- a/app/views/protected_branches/index.html.haml
+++ b/app/views/protected_branches/index.html.haml
@@ -19,12 +19,12 @@
.entry.clearfix
= f.label :name, "Branch"
.span3
- = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , { include_blank: "-- Select branch" }, { class: "span3" })
+ = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: "Select branch"}, {class: "chosen span3"})
= f.submit 'Protect', class: "primary btn"
- unless @branches.empty?
- %table.admin-table
+ %table
%thead
%tr
%th Name
@@ -46,6 +46,3 @@
%td
- if can? current_user, :admin_project, @project
= link_to 'Unprotect', [@project, branch], confirm: 'Are you sure?', method: :delete, class: "danger btn small"
-
-:javascript
- $('select#protected_branch_name').chosen();
diff --git a/app/views/refs/_head.html.haml b/app/views/refs/_head.html.haml
index 8825493a..3592f573 100644
--- a/app/views/refs/_head.html.haml
+++ b/app/views/refs/_head.html.haml
@@ -1,10 +1,11 @@
%ul.nav.nav-tabs
%li
- = form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form", remote: true do
- = select_tag "ref", grouped_options_refs, onchange: "$(this.form).trigger('submit');", class: "project-refs-select"
- = hidden_field_tag :destination, "tree"
- = hidden_field_tag :path, params[:path]
+ = render partial: 'shared/ref_switcher', locals: {destination: 'tree', path: params[:path]}
%li{class: "#{'active' if (controller.controller_name == "refs") }"}
= link_to tree_project_ref_path(@project, @ref) do
Source
-
+ %li.right
+ .input-prepend.project_clone_holder
+ %button{class: "btn small active", :"data-clone" => @project.ssh_url_to_repo} SSH
+ %button{class: "btn small", :"data-clone" => @project.http_url_to_repo} HTTP
+ = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select span5"
diff --git a/app/views/refs/_tree.html.haml b/app/views/refs/_tree.html.haml
index c231c407..55078718 100644
--- a/app/views/refs/_tree.html.haml
+++ b/app/views/refs/_tree.html.haml
@@ -13,7 +13,7 @@
= render partial: "refs/tree_file", locals: { name: tree.name, content: tree.data, file: tree }
- else
- contents = tree.contents
- %table#tree-slider.bordered-table.table{class: "table_#{@hex_path}" }
+ %table#tree-slider{class: "table_#{@hex_path}" }
%thead
%th Name
%th Last Update
@@ -43,25 +43,23 @@
%i.icon-file
= content.name
.file_content.wiki
- - if content.name =~ /\.(md|markdown)$/i
+ - if gitlab_markdown?(content.name)
= preserve do
= markdown(content.data)
- else
- = simple_format(content.data)
+ = raw GitHub::Markup.render(content.name, content.data)
:javascript
$(function(){
- $('.project-refs-select').chosen();
-
history.pushState({ path: this.path }, '', "#{@history_path}");
-
- });
-
- // Load last commit log for each file in tree
- $(window).load(function(){
- ajaxGet('#{@logs_path}');
});
+- unless tree.is_blob?
+ :javascript
+ // Load last commit log for each file in tree
+ $(window).load(function(){
+ ajaxGet('#{@logs_path}');
+ });
- if params[:path] && request.xhr?
:javascript
diff --git a/app/views/refs/_tree_file.html.haml b/app/views/refs/_tree_file.html.haml
index b5ed61bb..76173e24 100644
--- a/app/views/refs/_tree_file.html.haml
+++ b/app/views/refs/_tree_file.html.haml
@@ -2,17 +2,20 @@
.file_title
%i.icon-file
%span.file_name
- = name
+ = name.force_encoding('utf-8')
%small #{file.mode}
%span.options
= link_to "raw", blob_project_ref_path(@project, @ref, path: params[:path]), class: "btn very_small", target: "_blank"
= link_to "history", project_commits_path(@project, path: params[:path], ref: @ref), class: "btn very_small"
= link_to "blame", blame_file_project_ref_path(@project, @ref, path: params[:path]), class: "btn very_small"
- if file.text?
- - if name =~ /\.(md|markdown)$/i
+ - if gitlab_markdown?(name)
.file_content.wiki
= preserve do
= markdown(file.data)
+ - elsif markup?(name)
+ .file_content.wiki
+ = raw GitHub::Markup.render(name, file.data)
- else
.file_content.code
- unless file.empty?
diff --git a/app/views/refs/_tree_item.html.haml b/app/views/refs/_tree_item.html.haml
index 2e6bbf62..d4c4ee8d 100644
--- a/app/views/refs/_tree_item.html.haml
+++ b/app/views/refs/_tree_item.html.haml
@@ -2,7 +2,7 @@
%tr{ class: "tree-item #{tree_hex_class(content)}", url: tree_file_project_ref_path(@project, @ref, file) }
%td.tree-item-file-name
= tree_icon(content)
- = link_to truncate(content.name, length: 40), tree_file_project_ref_path(@project, @ref || @commit.id, file), remote: :true
+ %strong= link_to truncate(content.name, length: 40), tree_file_project_ref_path(@project, @ref || @commit.id, file), remote: :true
%td.tree_time_ago.cgray
- if index == 1
%span.log_loading
diff --git a/app/views/refs/blame.html.haml b/app/views/refs/blame.html.haml
index 34478d4b..eb66f597 100644
--- a/app/views/refs/blame.html.haml
+++ b/app/views/refs/blame.html.haml
@@ -38,8 +38,3 @@
= preserve do
%pre
= Gitlab::Encode.utf8 lines.join("\n")
-
-:javascript
- $(function(){
- $('.project-refs-select').chosen();
- });
diff --git a/app/views/refs/tree.js.haml b/app/views/refs/tree.js.haml
index 2eccf8c1..92e90579 100644
--- a/app/views/refs/tree.js.haml
+++ b/app/views/refs/tree.js.haml
@@ -6,5 +6,5 @@
// Load last commit log for each file in tree
$('#tree-slider').waitForImages(function() {
- ajaxGet('#{@logs_path}');
+ ajaxGet('#{@logs_path}');
});
diff --git a/app/views/repositories/_branch.html.haml b/app/views/repositories/_branch.html.haml
index cf8558ec..64a633be 100644
--- a/app/views/repositories/_branch.html.haml
+++ b/app/views/repositories/_branch.html.haml
@@ -11,7 +11,7 @@
%code= commit.short_id
= image_tag gravatar_icon(commit.author_email), class: "", width: 16
- = gfm truncate(commit.title, length: 40)
+ = gfm escape_once(truncate(commit.title, length: 40))
%span.update-author.right
= time_ago_in_words(commit.committed_date)
ago
diff --git a/app/views/repositories/_feed.html.haml b/app/views/repositories/_feed.html.haml
index ac4eb483..0c13551d 100644
--- a/app/views/repositories/_feed.html.haml
+++ b/app/views/repositories/_feed.html.haml
@@ -13,7 +13,7 @@
= link_to project_commits_path(@project, commit.id) do
%code= commit.short_id
= image_tag gravatar_icon(commit.author_email), class: "", width: 16
- = gfm truncate(commit.title, length: 40)
+ = gfm escape_once(truncate(commit.title, length: 40))
%td
%span.right.cgray
= time_ago_in_words(commit.committed_date)
diff --git a/app/views/repositories/branches.html.haml b/app/views/repositories/branches.html.haml
index 45004bdf..4c246c69 100644
--- a/app/views/repositories/branches.html.haml
+++ b/app/views/repositories/branches.html.haml
@@ -1,6 +1,6 @@
= render "repositories/branches_head"
- unless @branches.empty?
- %table.admin-table
+ %table
%thead
%tr
%th Name
diff --git a/app/views/repositories/show.html.haml b/app/views/repositories/show.html.haml
index a09cdd62..fd0abac8 100644
--- a/app/views/repositories/show.html.haml
+++ b/app/views/repositories/show.html.haml
@@ -1,6 +1,6 @@
= render "branches_head"
-%table.admin-table
+%table
%thead
%tr
%th Name
diff --git a/app/views/repositories/tags.html.haml b/app/views/repositories/tags.html.haml
index 7fc2c3bf..a4114586 100644
--- a/app/views/repositories/tags.html.haml
+++ b/app/views/repositories/tags.html.haml
@@ -1,6 +1,6 @@
= render "commits/head"
- unless @tags.empty?
- %table.admin-table
+ %table
%thead
%tr
%th Name
@@ -17,7 +17,7 @@
= link_to project_commit_path(@project, commit.id) do
%code= commit.short_id
= image_tag gravatar_icon(commit.author_email), class: "", width: 16
- = gfm truncate(commit.title, length: 40)
+ = gfm escape_once(truncate(commit.title, length: 40))
%td
%span.update-author.right
= time_ago_in_words(commit.committed_date)
diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml
index 9a0b4789..d85c24ec 100644
--- a/app/views/search/show.html.haml
+++ b/app/views/search/show.html.haml
@@ -3,8 +3,8 @@
= label_tag :search do
%strong Looking for
.input
- = text_field_tag :search, params[:search], placeholder: "issue 143", class: "input-xxlarge", id: "dashboard_search"
- = submit_tag 'Search', class: "btn btn-primary"
+ = search_field_tag :search, params[:search], placeholder: "issue 143", class: "input-xxlarge search-text-input", id: "dashboard_search"
+ = submit_tag 'Search', class: "btn primary wide"
- if params[:search].present?
%br
%h3
@@ -14,9 +14,10 @@
.search_results
.row
.span6
- %table.admin-table
- %tr
- %th Projects
+ %table
+ %thead
+ %tr
+ %th Projects
%tbody
- @projects.each do |project|
%tr
@@ -31,9 +32,10 @@
%td
%h4.nothing_here_message No Projects
%br
- %table.admin-table
- %tr
- %th Merge Requests
+ %table
+ %thead
+ %tr
+ %th Merge Requests
%tbody
- @merge_requests.each do |merge_request|
%tr
@@ -49,9 +51,10 @@
%td
%h4.nothing_here_message No Merge Requests
.span6
- %table.admin-table
- %tr
- %th Issues
+ %table
+ %thead
+ %tr
+ %th Issues
%tbody
- @issues.each do |issue|
%tr
diff --git a/app/views/shared/_ref_switcher.html.haml b/app/views/shared/_ref_switcher.html.haml
new file mode 100644
index 00000000..e0c89522
--- /dev/null
+++ b/app/views/shared/_ref_switcher.html.haml
@@ -0,0 +1,5 @@
+= form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do
+ = select_tag "ref", grouped_options_refs, class: "project-refs-select chosen"
+ = hidden_field_tag :destination, destination
+ - if respond_to?(:path)
+ = hidden_field_tag :path, path
diff --git a/app/views/snippets/_form.html.haml b/app/views/snippets/_form.html.haml
index b8d8c098..e61e61a7 100644
--- a/app/views/snippets/_form.html.haml
+++ b/app/views/snippets/_form.html.haml
@@ -16,7 +16,7 @@
.input= f.text_field :file_name, placeholder: "example.rb"
.clearfix
= f.label "Lifetime"
- .input= f.select :expires_at, lifetime_select_options, {}, style: "width:200px;"
+ .input= f.select :expires_at, lifetime_select_options, {}, {class: 'chosen span2'}
.clearfix
= f.label :content, "Code"
.input= f.text_area :content, class: "span8"
@@ -26,11 +26,3 @@
= link_to "Cancel", project_snippets_path(@project), class: " btn"
- unless @snippet.new_record?
.right= link_to 'Destroy', [@project, @snippet], confirm: 'Are you sure?', method: :delete, class: "btn right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}"
-
-
-
-:javascript
- $(function(){
- $('select#snippet_expires_at').chosen();
- });
-
diff --git a/app/views/snippets/index.html.haml b/app/views/snippets/index.html.haml
index 7229b587..515daec6 100644
--- a/app/views/snippets/index.html.haml
+++ b/app/views/snippets/index.html.haml
@@ -8,7 +8,7 @@
%br
To add new snippet - click on button.
-%table.admin-table
+%table
%thead
%tr
%th Title
diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml
index 0800b81d..4188a9f1 100644
--- a/app/views/snippets/show.html.haml
+++ b/app/views/snippets/show.html.haml
@@ -17,4 +17,4 @@
%div{class: current_user.dark_scheme ? "black" : ""}
= raw @snippet.colorize(options: { linenos: 'True'})
-= render "notes/notes", tid: @snippet.id, tt: "snippet"
+= render "notes/notes_with_form", tid: @snippet.id, tt: "snippet"
diff --git a/app/views/team_members/_form.html.haml b/app/views/team_members/_form.html.haml
index 208794b9..92167138 100644
--- a/app/views/team_members/_form.html.haml
+++ b/app/views/team_members/_form.html.haml
@@ -1,4 +1,5 @@
-%h3= "New Team member"
+%h3.page_title
+ = "New Team member(s)"
%hr
= form_for @team_member, as: :team_member, url: project_team_members_path(@project, @team_member) do |f|
-if @team_member.errors.any?
@@ -7,27 +8,16 @@
- @team_member.errors.full_messages.each do |msg|
%li= msg
+ %h6 1. Choose people you want in the team
.clearfix
- = f.label :user_id, "Name"
- .input= f.select(:user_id, User.not_in_project(@project).all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, { style: "width:300px" })
-
+ = f.label :user_ids, "People"
+ .input= select_tag(:user_ids, options_from_collection_for_select(User.not_in_project(@project).all, :id, :name), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true})
+ %h6 2. Set access level for them
.clearfix
= f.label :project_access, "Project Access"
- .input= f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, class: "project-access-select"
-
+ .input= select_tag :project_access, options_for_select(Project.access_options, @team_member.project_access), class: "project-access-select chosen"
.actions
- = f.submit 'Save', class: "btn primary"
- = link_to "Cancel", team_project_path(@project), class: "btn"
-
-:css
- form select {
- width:300px;
- }
-
-:javascript
- $('select#team_member_user_id').chosen();
- $('select#team_member_project_access').chosen();
- //$('select#team_member_repo_access').chosen();
- //$('select#team_member_project_access').chosen();
+ = f.submit 'Save', class: "btn save-btn"
+ = link_to "Cancel", project_team_index_path(@project), class: "btn cancel-btn"
diff --git a/app/views/team_members/_show.html.haml b/app/views/team_members/_show.html.haml
index 2dc4fb65..f68f8eb4 100644
--- a/app/views/team_members/_show.html.haml
+++ b/app/views/team_members/_show.html.haml
@@ -1,20 +1,26 @@
- user = member.user
- allow_admin = can? current_user, :admin_project, @project
%tr{id: dom_id(member), class: "team_member_row user_#{user.id}"}
- %td
- .right
- - if @project.owner == user
- %span.label Project Owner
- - if user.blocked
- %span.label Blocked
-
+ %td.span6
= link_to project_team_member_path(@project, member), title: user.name, class: "dark" do
= image_tag gravatar_icon(user.email, 40), class: "avatar s32"
= link_to project_team_member_path(@project, member), title: user.name, class: "dark" do
%strong= truncate(user.name, lenght: 40)
- %br
- %div.cgray= user.email
+ %br
+ %small.cgray= user.email
- %td
- = form_for(member, as: :team_member, url: project_team_member_path(@project, member)) do |f|
- = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select", disabled: !allow_admin
+ %td.span5
+ .right
+ - if current_user == user
+ %span.btn.disabled This is you!
+ - if @project.owner == user
+ %span.btn.disabled.success Owner
+ - elsif user.blocked
+ %span.btn.disabled.blocked Blocked
+ - elsif allow_admin
+ = link_to project_team_member_path(project_id: @project, id: member.id), confirm: remove_from_team_message(@project, member), method: :delete, class: "very_small btn danger" do
+ %i.icon-minus.icon-white
+
+ - if allow_admin
+ = form_for(member, as: :team_member, url: project_team_member_path(@project, member)) do |f|
+ = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2"
diff --git a/app/views/team_members/_team.html.haml b/app/views/team_members/_team.html.haml
new file mode 100644
index 00000000..a0c88b59
--- /dev/null
+++ b/app/views/team_members/_team.html.haml
@@ -0,0 +1,18 @@
+- grouper_project_members(@project).each do |access, members|
+ %table
+ %thead
+ %tr
+ %th.span7
+ = Project.access_options.key(access).pluralize
+ %th
+ %tbody
+ - members.each do |up|
+ = render(partial: 'team_members/show', locals: {member: up})
+
+
+:javascript
+ $(function(){
+ $('.repo-access-select, .project-access-select').live("change", function() {
+ $(this.form).submit();
+ });
+ })
diff --git a/app/views/projects/team.html.haml b/app/views/team_members/index.html.haml
similarity index 79%
rename from app/views/projects/team.html.haml
rename to app/views/team_members/index.html.haml
index e8a825c7..b3b7b72a 100644
--- a/app/views/projects/team.html.haml
+++ b/app/views/team_members/index.html.haml
@@ -1,4 +1,4 @@
-= render "project_head"
+= render "projects/project_head"
%h3.page_title
Team Members
%small (#{@project.users_projects.count})
@@ -10,6 +10,4 @@
Read more about project permissions
%strong= link_to "here", help_permissions_path, class: "vlink"
-
-= render partial: "team", locals: {project: @project}
-
+= render partial: "team_members/team", locals: {project: @project}
diff --git a/app/views/team_members/show.html.haml b/app/views/team_members/show.html.haml
index 6cb357cd..9d03cd2c 100644
--- a/app/views/team_members/show.html.haml
+++ b/app/views/team_members/show.html.haml
@@ -3,7 +3,7 @@
.team_member_show
- if can? current_user, :admin_project, @project
- = link_to 'Remove from team', project_team_member_path(project_id: @project, id: @team_member.id), confirm: 'Are you sure?', method: :delete, class: "right btn btn-danger"
+ = link_to 'Remove from team', project_team_member_path(project_id: @project, id: @team_member.id), confirm: 'Are you sure?', method: :delete, class: "right btn danger"
.profile_avatar_holder
= image_tag gravatar_icon(user.email, 60), class: "borders"
%h3
@@ -14,12 +14,12 @@
%hr
.back_link
%br
- = link_to team_project_path(@project), class: "" do
+ = link_to project_team_index_path(@project), class: "" do
← To team list
%br
.row
.span6
- %table.no-borders
+ %table.lite
%tr
%td Email
%td= mail_to user.email
@@ -39,7 +39,7 @@
%td Bio
%td= user.bio
.span6
- %table.no-borders
+ %table.lite
%tr
%td Member since
%td= @team_member.created_at.stamp("Aug 21, 2011")
diff --git a/app/views/votes/_votes_block.html.haml b/app/views/votes/_votes_block.html.haml
new file mode 100644
index 00000000..bded53b2
--- /dev/null
+++ b/app/views/votes/_votes_block.html.haml
@@ -0,0 +1,6 @@
+.votes.votes-block
+ .progress
+ .bar.bar-success{style: "width: #{votable.upvotes_in_percent}%;"}
+ .bar.bar-danger{style: "width: #{votable.downvotes_in_percent}%;"}
+ .upvotes= "#{votable.upvotes} up"
+ .downvotes= "#{votable.downvotes} down"
diff --git a/app/views/votes/_votes_inline.html.haml b/app/views/votes/_votes_inline.html.haml
new file mode 100644
index 00000000..91bd200d
--- /dev/null
+++ b/app/views/votes/_votes_inline.html.haml
@@ -0,0 +1,6 @@
+.votes.votes-inline
+ .upvotes= votable.upvotes
+ .progress
+ .bar.bar-success{style: "width: #{votable.upvotes_in_percent}%;"}
+ .bar.bar-danger{style: "width: #{votable.downvotes_in_percent}%;"}
+ .downvotes= votable.downvotes
diff --git a/app/views/wikis/_form.html.haml b/app/views/wikis/_form.html.haml
index 6b6411be..b05d0a78 100644
--- a/app/views/wikis/_form.html.haml
+++ b/app/views/wikis/_form.html.haml
@@ -14,13 +14,14 @@
.middle_box_content
.input
%span.cgray
- Wiki content is parsed with #{link_to "Markdown", "http://en.wikipedia.org/wiki/Markdown"}.
- To add link to new page you can just type
+ Wiki content is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
+ To link to a (new) page you can just type
%code [Link Title](page-slug)
+ \.
.bottom_box_content
= f.label :content
.input= f.text_area :content, class: 'span8'
.actions
- = f.submit 'Save', class: "primary btn"
- = link_to "Cancel", project_wiki_path(@project, :index), class: "btn"
+ = f.submit 'Save', class: "save-btn btn"
+ = link_to "Cancel", project_wiki_path(@project, :index), class: "btn cancel-btn"
diff --git a/app/views/wikis/history.html.haml b/app/views/wikis/history.html.haml
index e31c5dc2..0a81817c 100644
--- a/app/views/wikis/history.html.haml
+++ b/app/views/wikis/history.html.haml
@@ -2,7 +2,7 @@
%span.cgray History for
= @wikis.last.title
%br
-%table.admin-table
+%table
%thead
%tr
%th #
diff --git a/app/views/wikis/pages.html.haml b/app/views/wikis/pages.html.haml
index 2bfd0deb..7421d8f9 100644
--- a/app/views/wikis/pages.html.haml
+++ b/app/views/wikis/pages.html.haml
@@ -1,6 +1,6 @@
%h3.page_title All Pages
%br
-%table.admin-table
+%table
%thead
%tr
%th Title
diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml
index fc235227..579ea1b3 100644
--- a/app/views/wikis/show.html.haml
+++ b/app/views/wikis/show.html.haml
@@ -21,4 +21,4 @@
Delete this page
%hr
-.wiki_notes#notes= render "notes/notes", tid: @wiki.id, tt: "wiki"
+.wiki_notes#notes= render "notes/notes_with_form", tid: @wiki.id, tt: "wiki"
diff --git a/config/application.rb b/config/application.rb
index ecd88b15..ad41f196 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -23,7 +23,7 @@ module Gitlab
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
# Activate observers that should always be running.
- config.active_record.observers = :mailer_observer, :activity_observer, :project_observer, :key_observer, :issue_observer, :user_observer, :system_hook_observer
+ config.active_record.observers = :mailer_observer, :activity_observer, :project_observer, :key_observer, :issue_observer, :user_observer, :system_hook_observer, :users_project_observer
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
diff --git a/config/cucumber.yml b/config/cucumber.yml
deleted file mode 100644
index 19b288df..00000000
--- a/config/cucumber.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-<%
-rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
-rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
-std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip"
-%>
-default: <%= std_opts %> features
-wip: --tags @wip:3 --wip features
-rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip
diff --git a/config/environment.rb b/config/environment.rb
index c880a7ad..3b186a9d 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -3,5 +3,3 @@ require File.expand_path('../application', __FILE__)
# Initialize the rails application
Gitlab::Application.initialize!
-
-require File.join(Rails.root, "lib", "gitlab", "git_host")
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index be36ee6d..28323484 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -25,18 +25,55 @@ app:
# backup_keep_time: 604800 # default: 0 (forever) (in seconds)
# disable_gravatar: true # default: false - Disable user avatars from Gravatar.com
+
#
-# 2. Advanced settings:
+# 2. Auth settings
+# ==========================
+ldap:
+ enabled: false
+ host: '_your_ldap_server'
+ base: '_the_base_where_you_search_for_users'
+ port: 636
+ uid: 'sAMAccountName'
+ method: 'ssl' # plain
+ bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
+ password: '_the_password_of_the_bind_user'
+
+omniauth:
+ # Enable ability for users
+ # to login via twitter, google ..
+ enabled: false
+
+ # IMPORTANT!
+ # It allows user to login without having user account
+ allow_single_sign_on: false
+ block_auto_created_users: true
+
+ # Auth providers
+ providers:
+ # - { name: 'google_oauth2', app_id: 'YOUR APP ID',
+ # app_secret: 'YOUR APP SECRET',
+ # args: { access_type: 'offline', approval_prompt: '' } }
+ # - { name: 'twitter', app_id: 'YOUR APP ID',
+ # app_secret: 'YOUR APP SECRET'}
+ # - { name: 'github', app_id: 'YOUR APP ID',
+ # app_secret: 'YOUR APP SECRET' }
+
+
+#
+# 3. Advanced settings:
# ==========================
# Git Hosting configuration
git_host:
admin_uri: git@localhost:gitolite-admin
base_path: /home/git/repositories/
- # host: localhost
+ hooks_path: /home/git/.gitolite/hooks/
+ gitolite_admin_key: gitlab
git_user: git
upload_pack: true
receive_pack: true
+ # host: localhost
# port: 22
# Git settings
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 8165d6c2..7a7ca43f 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -6,7 +6,7 @@ class Settings < Settingslogic
self.web['protocol'] ||= web.https ? "https" : "http"
end
- def web_host
+ def web_host
self.web['host'] ||= 'localhost'
end
@@ -14,11 +14,11 @@ class Settings < Settingslogic
self.email['from'] ||= ("notify@" + web_host)
end
- def url
+ def url
self['url'] ||= build_url
- end
+ end
- def web_port
+ def web_port
if web.https
web['port'] = 443
else
@@ -36,7 +36,7 @@ class Settings < Settingslogic
raw_url << web_host
if web_custom_port?
- raw_url << ":#{web_port}"
+ raw_url << ":#{web_port}"
end
raw_url
@@ -66,6 +66,10 @@ class Settings < Settingslogic
git_host['base_path'] || '/home/git/repositories/'
end
+ def git_hooks_path
+ git_host['hooks_path'] || '/home/git/share/gitolite/hooks/'
+ end
+
def git_upload_pack
if git_host['upload_pack'] != false
true
@@ -98,6 +102,10 @@ class Settings < Settingslogic
git_host['admin_uri'] || 'git@localhost:gitolite-admin'
end
+ def gitolite_admin_key
+ git_host['gitolite_admin_key'] || 'gitlab'
+ end
+
def default_projects_limit
app['default_projects_limit'] || 10
end
@@ -112,6 +120,22 @@ class Settings < Settingslogic
app['backup_keep_time'] || 0
end
+ def ldap_enabled?
+ ldap && ldap['enabled']
+ rescue Settingslogic::MissingSetting
+ false
+ end
+
+ def omniauth_enabled?
+ omniauth && omniauth['enabled']
+ rescue Settingslogic::MissingSetting
+ false
+ end
+
+ def omniauth_providers
+ (omniauth_enabled? && omniauth['providers']) || []
+ end
+
def disable_gravatar?
app['disable_gravatar'] || false
end
diff --git a/config/initializers/5_backend.rb b/config/initializers/5_backend.rb
new file mode 100644
index 00000000..85f747ac
--- /dev/null
+++ b/config/initializers/5_backend.rb
@@ -0,0 +1,5 @@
+# GIT over HTTP
+require Rails.root.join("lib", "gitlab", "backend", "grack_auth")
+
+# GITOLITE backend
+require Rails.root.join("lib", "gitlab", "backend", "gitolite")
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 54011ba5..8f3cef5a 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -204,4 +204,21 @@ Devise.setup do |config|
# manager.intercept_401 = false
# manager.default_strategies(:scope => :user).unshift :some_external_strategy
# end
+
+ gl = Gitlab.config
+
+ if gl.ldap_enabled?
+ config.omniauth :ldap,
+ :host => gl.ldap['host'],
+ :base => gl.ldap['base'],
+ :uid => gl.ldap['uid'],
+ :port => gl.ldap['port'],
+ :method => gl.ldap['method'],
+ :bind_dn => gl.ldap['bind_dn'],
+ :password => gl.ldap['password']
+ end
+
+ gl.omniauth_providers.each do |gl_provider|
+ config.omniauth gl_provider['name'].to_sym, gl_provider['app_id'], gl_provider['app_secret']
+ end
end
diff --git a/config/initializers/kaminari_config.rb b/config/initializers/kaminari_config.rb
new file mode 100644
index 00000000..3cbe9a05
--- /dev/null
+++ b/config/initializers/kaminari_config.rb
@@ -0,0 +1,10 @@
+Kaminari.configure do |config|
+ config.default_per_page = 20
+ config.max_per_page = 100
+ # config.window = 4
+ # config.outer_window = 0
+ # config.left = 0
+ # config.right = 0
+ # config.page_method_name = :page
+ # config.param_name = :page
+end
diff --git a/config/initializers/omniauth.rb.sample b/config/initializers/omniauth.rb.sample
deleted file mode 100644
index 6e844efd..00000000
--- a/config/initializers/omniauth.rb.sample
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copy this file to 'omniauth.rb' and configure it as necessary.
-# The wiki has further details on configuring each provider.
-
-Devise.setup do |config|
- # config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo'
-
- # config.omniauth :ldap,
- # :host => 'YOUR_LDAP_SERVER',
- # :base => 'THE_BASE_WHERE_YOU_SEARCH_FOR_USERS',
- # :uid => 'sAMAccountName',
- # :port => 389,
- # :method => :plain,
- # :bind_dn => 'THE_FULL_DN_OF_THE_USER_YOU_WILL_BIND_WITH',
- # :password => 'THE_PASSWORD_OF_THE_BIND_USER'
-end
diff --git a/config/initializers/resque.rb b/config/initializers/resque.rb
new file mode 100644
index 00000000..b333ceee
--- /dev/null
+++ b/config/initializers/resque.rb
@@ -0,0 +1,8 @@
+rails_root = ENV['RAILS_ROOT'] || File.dirname(__FILE__) + '/../..'
+rails_env = ENV['RAILS_ENV'] || 'development'
+config_file = File.join(rails_root, 'config', 'resque.yml')
+
+if File.exists?(config_file)
+ resque_config = YAML.load_file(config_file)
+ Resque.redis = resque_config[rails_env]
+end
diff --git a/config/resque.yml.example b/config/resque.yml.example
new file mode 100644
index 00000000..cd3d4874
--- /dev/null
+++ b/config/resque.yml.example
@@ -0,0 +1,3 @@
+development: localhost:6379
+test: localhost:6379
+production: redis.example.com:6379
diff --git a/config/routes.rb b/config/routes.rb
index 97594d57..cfb9bdb9 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -10,7 +10,7 @@ Gitlab::Application.routes.draw do
# Optionally, enable Resque here
require 'resque/server'
- mount Resque::Server.new, at: '/info/resque'
+ mount Resque::Server => '/info/resque', as: 'resque'
# Enable Grack support
mount Grack::Bundle.new({
@@ -23,14 +23,14 @@ Gitlab::Application.routes.draw do
#
# Help
#
- get 'help' => 'help#index'
- get 'help/permissions' => 'help#permissions'
- get 'help/workflow' => 'help#workflow'
- get 'help/api' => 'help#api'
- get 'help/web_hooks' => 'help#web_hooks'
+ get 'help' => 'help#index'
+ get 'help/permissions' => 'help#permissions'
+ get 'help/workflow' => 'help#workflow'
+ get 'help/api' => 'help#api'
+ get 'help/web_hooks' => 'help#web_hooks'
get 'help/system_hooks' => 'help#system_hooks'
- get 'help/markdown' => 'help#markdown'
- get 'help/ssh' => 'help#ssh'
+ get 'help/markdown' => 'help#markdown'
+ get 'help/ssh' => 'help#ssh'
#
# Admin Area
@@ -43,23 +43,19 @@ Gitlab::Application.routes.draw do
put :unblock
end
end
- resources :projects, :constraints => { :id => /[^\/]+/ } do
+ resources :projects, constraints: { id: /[^\/]+/ } do
member do
get :team
put :team_update
end
end
- resources :team_members, :only => [:edit, :update, :destroy]
- get 'mailer/preview_note'
- get 'mailer/preview_user_new'
- get 'mailer/preview_issue_new'
-
- resources :hooks, :only => [:index, :create, :destroy] do
+ resources :team_members, only: [:edit, :update, :destroy]
+ resources :hooks, only: [:index, :create, :destroy] do
get :test
end
- resource :logs
- resource :resque, :controller => 'resque'
- root :to => "dashboard#index"
+ resource :logs, only: [:show]
+ resource :resque, controller: 'resque', only: [:show]
+ root to: "dashboard#index"
end
get "errors/githost"
@@ -67,38 +63,39 @@ Gitlab::Application.routes.draw do
#
# Profile Area
#
- get "profile/password", :to => "profile#password"
- put "profile/password", :to => "profile#password_update"
- get "profile/token", :to => "profile#token"
- put "profile/reset_private_token", :to => "profile#reset_private_token"
- get "profile", :to => "profile#show"
- get "profile/design", :to => "profile#design"
- put "profile/update", :to => "profile#update"
+ get "profile/account" => "profile#account"
+ get "profile/history" => "profile#history"
+ put "profile/password" => "profile#password_update"
+ get "profile/token" => "profile#token"
+ put "profile/reset_private_token" => "profile#reset_private_token"
+ get "profile" => "profile#show"
+ get "profile/design" => "profile#design"
+ put "profile/update" => "profile#update"
+
resources :keys
#
# Dashboard Area
#
- get "dashboard", :to => "dashboard#index"
- get "dashboard/issues", :to => "dashboard#issues"
- get "dashboard/merge_requests", :to => "dashboard#merge_requests"
+ get "dashboard" => "dashboard#index"
+ get "dashboard/issues" => "dashboard#issues"
+ get "dashboard/merge_requests" => "dashboard#merge_requests"
- resources :projects, :constraints => { :id => /[^\/]+/ }, :only => [:new, :create]
+ resources :projects, constraints: { id: /[^\/]+/ }, only: [:new, :create]
- devise_for :users, :controllers => { :omniauth_callbacks => :omniauth_callbacks }
+ devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks }
#
# Project Area
#
- resources :projects, :constraints => { :id => /[^\/]+/ }, :except => [:new, :create, :index], :path => "/" do
+ resources :projects, constraints: { id: /[^\/]+/ }, except: [:new, :create, :index], path: "/" do
member do
- get "team"
get "wall"
get "graph"
get "files"
end
- resources :wikis, :only => [:show, :edit, :destroy, :create] do
+ resources :wikis, only: [:show, :edit, :destroy, :create] do
collection do
get :pages
end
@@ -117,46 +114,45 @@ Gitlab::Application.routes.draw do
end
resources :deploy_keys
- resources :protected_branches, :only => [:index, :create, :destroy]
+ resources :protected_branches, only: [:index, :create, :destroy]
- resources :refs, :only => [], :path => "/" do
+ resources :refs, only: [], path: "/" do
collection do
get "switch"
end
member do
- get "tree", :constraints => { :id => /[a-zA-Z.\/0-9_\-]+/ }
- get "logs_tree", :constraints => { :id => /[a-zA-Z.\/0-9_\-]+/ }
+ get "tree", constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }
+ get "logs_tree", constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }
get "blob",
- :constraints => {
- :id => /[a-zA-Z.0-9\/_\-]+/,
- :path => /.*/
+ constraints: {
+ id: /[a-zA-Z.0-9\/_\-]+/,
+ path: /.*/
}
-
# tree viewer
get "tree/:path" => "refs#tree",
- :as => :tree_file,
- :constraints => {
- :id => /[a-zA-Z.0-9\/_\-]+/,
- :path => /.*/
+ as: :tree_file,
+ constraints: {
+ id: /[a-zA-Z.0-9\/_\-]+/,
+ path: /.*/
}
# tree viewer
get "logs_tree/:path" => "refs#logs_tree",
- :as => :logs_file,
- :constraints => {
- :id => /[a-zA-Z.0-9\/_\-]+/,
- :path => /.*/
+ as: :logs_file,
+ constraints: {
+ id: /[a-zA-Z.0-9\/_\-]+/,
+ path: /.*/
}
# blame
get "blame/:path" => "refs#blame",
- :as => :blame_file,
- :constraints => {
- :id => /[a-zA-Z.0-9\/_\-]+/,
- :path => /.*/
+ as: :blame_file,
+ constraints: {
+ id: /[a-zA-Z.0-9\/_\-]+/,
+ path: /.*/
}
end
end
@@ -181,7 +177,7 @@ Gitlab::Application.routes.draw do
end
end
- resources :hooks, :only => [:index, :create, :destroy] do
+ resources :hooks, only: [:index, :create, :destroy] do
member do
get :test
end
@@ -195,20 +191,24 @@ Gitlab::Application.routes.draw do
get :patch
end
end
+ resources :team, controller: 'team_members', only: [:index]
resources :team_members
resources :milestones
+ resources :labels, only: [:index]
resources :issues do
+
collection do
post :sort
post :bulk_update
get :search
end
end
- resources :notes, :only => [:index, :create, :destroy] do
+ resources :notes, only: [:index, :create, :destroy] do
collection do
post :preview
end
end
end
- root :to => "dashboard#index"
+
+ root to: "dashboard#index"
end
diff --git a/config/unicorn.rb.orig b/config/unicorn.rb.example
similarity index 100%
rename from config/unicorn.rb.orig
rename to config/unicorn.rb.example
diff --git a/db/fixtures/test/001_repo.rb b/db/fixtures/test/001_repo.rb
index ebf005a1..67d4e7bf 100644
--- a/db/fixtures/test/001_repo.rb
+++ b/db/fixtures/test/001_repo.rb
@@ -1,15 +1,23 @@
-# create tmp dir if not exist
-tmp_dir = File.join(Rails.root, "tmp")
-Dir.mkdir(tmp_dir) unless File.exists?(tmp_dir)
+require 'fileutils'
-# Create dir for test repo
-repo_dir = File.join(Rails.root, "tmp", "tests")
-Dir.mkdir(repo_dir) unless File.exists?(repo_dir)
+print "Unpacking seed repository..."
-`cp spec/seed_project.tar.gz tmp/tests/`
-Dir.chdir(repo_dir)
-`tar -xf seed_project.tar.gz`
-3.times do |i|
-`cp -r gitlabhq/ gitlabhq_#{i}/`
-puts "Unpacked seed repo - tmp/tests/gitlabhq_#{i}"
+SEED_REPO = 'seed_project.tar.gz'
+REPO_PATH = File.join(Rails.root, 'tmp', 'repositories')
+
+# Make whatever directories we need to make
+FileUtils.mkdir_p(REPO_PATH)
+
+# Copy the archive to the repo path
+FileUtils.cp(File.join(Rails.root, 'spec', SEED_REPO), REPO_PATH)
+
+# chdir to the repo path
+FileUtils.cd(REPO_PATH) do
+ # Extract the archive
+ `tar -xf #{SEED_REPO}`
+
+ # Remove the copy
+ FileUtils.rm(SEED_REPO)
end
+
+puts ' done.'
diff --git a/db/migrate/20120905043334_set_default_branch_default_to_nil.rb b/db/migrate/20120905043334_set_default_branch_default_to_nil.rb
new file mode 100644
index 00000000..f5956fe8
--- /dev/null
+++ b/db/migrate/20120905043334_set_default_branch_default_to_nil.rb
@@ -0,0 +1,12 @@
+class SetDefaultBranchDefaultToNil < ActiveRecord::Migration
+ def up
+ # Set the default_branch to allow nil, and default it to nil
+ change_column_null(:projects, :default_branch, true)
+ change_column_default(:projects, :default_branch, nil)
+ end
+
+ def down
+ change_column_null(:projects, :default_branch, false)
+ change_column_default(:projects, :default_branch, 'master')
+ end
+end
diff --git a/db/pkey.example b/db/pkey.example
deleted file mode 100644
index ae045772..00000000
--- a/db/pkey.example
+++ /dev/null
@@ -1,3 +0,0 @@
-AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4
-596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4
-soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=
diff --git a/db/schema.rb b/db/schema.rb
index 46461e44..00bb5523 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20120729131232) do
+ActiveRecord::Schema.define(:version => 20120905043334) do
create_table "events", :force => true do |t|
t.string "target_type"
@@ -98,16 +98,16 @@ ActiveRecord::Schema.define(:version => 20120729131232) do
t.string "name"
t.string "path"
t.text "description"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.boolean "private_flag", :default => true, :null => false
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.boolean "private_flag", :default => true, :null => false
t.string "code"
t.integer "owner_id"
- t.string "default_branch", :default => "master", :null => false
- t.boolean "issues_enabled", :default => true, :null => false
- t.boolean "wall_enabled", :default => true, :null => false
- t.boolean "merge_requests_enabled", :default => true, :null => false
- t.boolean "wiki_enabled", :default => true, :null => false
+ t.string "default_branch"
+ t.boolean "issues_enabled", :default => true, :null => false
+ t.boolean "wall_enabled", :default => true, :null => false
+ t.boolean "merge_requests_enabled", :default => true, :null => false
+ t.boolean "wiki_enabled", :default => true, :null => false
end
create_table "protected_branches", :force => true do |t|
diff --git a/doc/api/README.md b/doc/api/README.md
index e0111966..36a36f8f 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -1,10 +1,8 @@
-# Gitlab API
+# GitLab API
-All API requests require authentication. You need to pass `private_token` parameter to authenticate.
+All API requests require authentication. You need to pass a `private_token` parameter to authenticate. You can find or reset your private token in your profile.
-To get or reset your token visit your profile.
-
-If no or invalid `private_token` provided error message will be returned with status code 401:
+If no, or an invalid, `private_token` is provided then an error message will be returned with status code 401:
```json
{
@@ -12,10 +10,9 @@ If no or invalid `private_token` provided error message will be returned with st
}
```
-API requests should be prefixed with `api` and the API version.
-API version is equal to Gitlab major version number and defined in `lib/api.rb`.
+API requests should be prefixed with `api` and the API version. The API version is equal to the GitLab major version number, which is defined in `lib/api.rb`.
-Example of valid API request:
+Example of a valid API request:
```
GET http://example.com/api/v2/projects?private_token=QVy1PB7sTxfy4pqfZM1U
@@ -23,8 +20,19 @@ GET http://example.com/api/v2/projects?private_token=QVy1PB7sTxfy4pqfZM1U
The API uses JSON to serialize data. You don't need to specify `.json` at the end of API URL.
+#### Pagination
+
+When listing resources you can pass the following parameters:
+
++ `page` (default: `1`) - page number
++ `per_page` (default: `20`, max: `100`) - how many items to list per page
+
## Contents
+ [Users](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/users.md)
++ [Session](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/session.md)
+ [Projects](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/projects.md)
++ [Snippets](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/snippets.md)
++ [Repositories](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/repositories.md)
+ [Issues](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/issues.md)
++ [Milestones](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/milestones.md)
diff --git a/doc/api/milestones.md b/doc/api/milestones.md
new file mode 100644
index 00000000..f68d8eb7
--- /dev/null
+++ b/doc/api/milestones.md
@@ -0,0 +1,57 @@
+## List project milestones
+
+Get a list of project milestones.
+
+```
+GET /projects/:id/milestones
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
+
+## Single milestone
+
+Get a single project milestone.
+
+```
+GET /projects/:id/milestones/:milestone_id
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `milestone_id` (required) - The ID of a project milestone
+
+## New milestone
+
+Create a new project milestone.
+
+```
+POST /projects/:id/milestones
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `milestone_id` (required) - The ID of a project milestone
++ `title` (required) - The title of an milestone
++ `description` (optional) - The description of the milestone
++ `due_date` (optional) - The due date of the milestone
+
+## Edit milestone
+
+Update an existing project milestone.
+
+```
+PUT /projects/:id/milestones/:milestone_id
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `milestone_id` (required) - The ID of a project milestone
++ `title` (optional) - The title of a milestone
++ `description` (optional) - The description of a milestone
++ `due_date` (optional) - The due date of the milestone
++ `closed` (optional) - The status of the milestone
diff --git a/doc/api/projects.md b/doc/api/projects.md
index ead31003..d06a41c2 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -1,6 +1,6 @@
## List projects
-Get a list of authenticated user's projects.
+Get a list of projects owned by the authenticated user.
```
GET /projects
@@ -55,7 +55,7 @@ GET /projects
## Single project
-Get an authenticated user's project.
+Get a specific project, identified by project ID, which is owned by the authentication user.
```
GET /projects/:id
@@ -89,235 +89,153 @@ Parameters:
}
```
-## Project repository branches
+## Create project
-Get a list of project repository branches sorted by name alphabetically.
+Create new project owned by user
```
-GET /projects/:id/repository/branches
+POST /projects
+```
+
+Parameters:
+
++ `name` (required) - new project name
++ `code` (optional) - new project code, uses project name if not set
++ `path` (optional) - new project path, uses project name if not set
++ `description` (optional) - short project description
++ `default_branch` (optional) - 'master' by default
++ `issues_enabled` (optional) - enabled by default
++ `wall_enabled` (optional) - enabled by default
++ `merge_requests_enabled` (optional) - enabled by default
++ `wiki_enabled` (optional) - enabled by default
+
+Will return created project with status `201 Created` on success, or `404 Not
+found` on fail.
+
+## List project team members
+
+Get a list of project team members.
+
+```
+GET /projects/:id/members
```
Parameters:
+ `id` (required) - The ID or code name of a project
-```json
-[
- {
- "name": "master",
- "commit": {
- "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
- "parents": [
- {
- "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
- }
- ],
- "tree": "46e82de44b1061621357f24c05515327f2795a95",
- "message": "add projects API",
- "author": {
- "name": "John Smith",
- "email": "john@example.com"
- },
- "committer": {
- "name": "John Smith",
- "email": "john@example.com"
- },
- "authored_date": "2012-06-27T05:51:39-07:00",
- "committed_date": "2012-06-28T03:44:20-07:00"
- }
- }
-]
-```
+## Get project team member
-Get a single project repository branch.
+Get a project team member.
```
-GET /projects/:id/repository/branches/:branch
+GET /projects/:id/members/:user_id
```
Parameters:
+ `id` (required) - The ID or code name of a project
-+ `branch` (required) - The name of the branch
++ `user_id` (required) - The ID of a user
```json
{
- "name": "master",
- "commit": {
- "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
- "parents": [
- {
- "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
- }
- ],
- "tree": "46e82de44b1061621357f24c05515327f2795a95",
- "message": "add projects API",
- "author": {
- "name": "John Smith",
- "email": "john@example.com"
- },
- "committer": {
- "name": "John Smith",
- "email": "john@example.com"
- },
- "authored_date": "2012-06-27T05:51:39-07:00",
- "committed_date": "2012-06-28T03:44:20-07:00"
- }
-}
-```
-## Project repository tags
-
-Get a list of project repository tags sorted by name in reverse alphabetical order.
-
-```
-GET /projects/:id/repository/tags
-```
-
-Parameters:
-
-+ `id` (required) - The ID or code name of a project
-
-```json
-[
- {
- "name": "v1.0.0",
- "commit": {
- "id": "2695effb5807a22ff3d138d593fd856244e155e7",
- "parents": [
-
- ],
- "tree": "38017f2f189336fe4497e9d230c5bb1bf873f08d",
- "message": "Initial commit",
- "author": {
- "name": "John Smith",
- "email": "john@example.com"
- },
- "committer": {
- "name": "Jack Smith",
- "email": "jack@example.com"
- },
- "authored_date": "2012-05-28T04:42:42-07:00",
- "committed_date": "2012-05-28T04:42:42-07:00"
- }
- }
-]
-```
-
-# Project Snippets
-
-## List snippets
-
-Not implemented.
-
-## Single snippet
-
-Get a project snippet.
-
-```
-GET /projects/:id/snippets/:snippet_id
-```
-
-Parameters:
-
-+ `id` (required) - The ID or code name of a project
-+ `snippet_id` (required) - The ID of a project's snippet
-
-```json
-{
"id": 1,
- "title": "test",
- "file_name": "add.rb",
- "author": {
- "id": 1,
- "email": "john@example.com",
- "name": "John Smith",
- "blocked": false,
- "created_at": "2012-05-23T08:00:58Z"
- },
- "expires_at": null,
- "updated_at": "2012-06-28T10:52:04Z",
- "created_at": "2012-06-28T10:52:04Z"
+ "email": "john@example.com",
+ "name": "John Smith",
+ "blocked": false,
+ "created_at": "2012-05-23T08:00:58Z",
+ "access_level": 40
}
```
-## Snippet content
+## Add project team member
-Get a raw project snippet.
+Add a user to a project team.
```
-GET /projects/:id/snippets/:snippet_id/raw
+POST /projects/:id/members
```
Parameters:
+ `id` (required) - The ID or code name of a project
-+ `snippet_id` (required) - The ID of a project's snippet
++ `user_id` (required) - The ID of a user to add
++ `access_level` (required) - Project access level
-## New snippet
+Will return status `201 Created` on success, or `404 Not found` on fail.
-Create a new project snippet.
+## Edit project team member
+
+Update project team member to specified access level.
```
-POST /projects/:id/snippets
+PUT /projects/:id/members/:user_id
```
Parameters:
+ `id` (required) - The ID or code name of a project
-+ `title` (required) - The title of a snippet
-+ `file_name` (required) - The name of a snippet file
-+ `lifetime` (optional) - The expiration date of a snippet
-+ `code` (required) - The content of a snippet
++ `user_id` (required) - The ID of a team member
++ `access_level` (required) - Project access level
-Will return created snippet with status `201 Created` on success, or `404 Not found` on fail.
+Will return status `200 OK` on success, or `404 Not found` on fail.
-## Edit snippet
+## Remove project team member
-Update an existing project snippet.
+Removes user from project team.
```
-PUT /projects/:id/snippets/:snippet_id
+DELETE /projects/:id/members/:user_id
```
Parameters:
+ `id` (required) - The ID or code name of a project
-+ `snippet_id` (required) - The ID of a project's snippet
-+ `title` (optional) - The title of a snippet
-+ `file_name` (optional) - The name of a snippet file
-+ `lifetime` (optional) - The expiration date of a snippet
-+ `code` (optional) - The content of a snippet
-
-Will return updated snippet with status `200 OK` on success, or `404 Not found` on fail.
-
-## Delete snippet
-
-Delete existing project snippet.
-
-```
-DELETE /projects/:id/snippets/:snippet_id
-```
-
-Parameters:
-
-+ `id` (required) - The ID or code name of a project
-+ `snippet_id` (required) - The ID of a project's snippet
++ `user_id` (required) - The ID of a team member
Status code `200` will be returned on success.
-## Raw blob content
+## Get project hooks
-Get the raw file contents for a file.
+Get hooks for project
```
-GET /projects/:id/repository/commits/:sha/blob
+GET /projects/:id/hooks
```
Parameters:
+ `id` (required) - The ID or code name of a project
-+ `sha` (required) - The commit or branch name
-+ `filepath` (required) - The path the file
-Will return the raw file contents.
+Will return hooks with status `200 OK` on success, or `404 Not found` on fail.
+
+## Add project hook
+
+Add hook to project
+
+```
+POST /projects/:id/hooks
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `url` (required) - The hook URL
+
+Will return status `201 Created` on success, or `404 Not found` on fail.
+
+## Delete project hook
+
+Delete hook from project
+
+```
+DELETE /projects/:id/hooks
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `hook_id` (required) - The ID of hook to delete
+
+Will return status `200 OK` on success, or `404 Not found` on fail.
diff --git a/doc/api/repositories.md b/doc/api/repositories.md
new file mode 100644
index 00000000..487ad9b2
--- /dev/null
+++ b/doc/api/repositories.md
@@ -0,0 +1,166 @@
+## Project repository branches
+
+Get a list of repository branches from a project, sorted by name alphabetically.
+
+```
+GET /projects/:id/repository/branches
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
+
+```json
+[
+ {
+ "name": "master",
+ "commit": {
+ "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
+ "parents": [
+ {
+ "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
+ }
+ ],
+ "tree": "46e82de44b1061621357f24c05515327f2795a95",
+ "message": "add projects API",
+ "author": {
+ "name": "John Smith",
+ "email": "john@example.com"
+ },
+ "committer": {
+ "name": "John Smith",
+ "email": "john@example.com"
+ },
+ "authored_date": "2012-06-27T05:51:39-07:00",
+ "committed_date": "2012-06-28T03:44:20-07:00"
+ }
+ }
+]
+```
+
+## Project repository branch
+
+Get a single project repository branch.
+
+```
+GET /projects/:id/repository/branches/:branch
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `branch` (required) - The name of the branch
+
+```json
+{
+ "name": "master",
+ "commit": {
+ "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
+ "parents": [
+ {
+ "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
+ }
+ ],
+ "tree": "46e82de44b1061621357f24c05515327f2795a95",
+ "message": "add projects API",
+ "author": {
+ "name": "John Smith",
+ "email": "john@example.com"
+ },
+ "committer": {
+ "name": "John Smith",
+ "email": "john@example.com"
+ },
+ "authored_date": "2012-06-27T05:51:39-07:00",
+ "committed_date": "2012-06-28T03:44:20-07:00"
+ }
+}
+```
+
+## Project repository tags
+
+Get a list of repository tags from a project, sorted by name in reverse alphabetical order.
+
+```
+GET /projects/:id/repository/tags
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
+
+```json
+[
+ {
+ "name": "v1.0.0",
+ "commit": {
+ "id": "2695effb5807a22ff3d138d593fd856244e155e7",
+ "parents": [
+
+ ],
+ "tree": "38017f2f189336fe4497e9d230c5bb1bf873f08d",
+ "message": "Initial commit",
+ "author": {
+ "name": "John Smith",
+ "email": "john@example.com"
+ },
+ "committer": {
+ "name": "Jack Smith",
+ "email": "jack@example.com"
+ },
+ "authored_date": "2012-05-28T04:42:42-07:00",
+ "committed_date": "2012-05-28T04:42:42-07:00"
+ }
+ }
+]
+```
+
+## Project repository commits
+
+Get a list of repository commits in a project.
+
+```
+GET /projects/:id/repository/commits
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `ref_name` (optional) - The name of a repository branch or tag
+
+```json
+[
+ {
+ "id": "ed899a2f4b50b4370feeea94676502b42383c746",
+ "short_id": "ed899a2f4b5",
+ "title": "Replace sanitize with escape once",
+ "author_name": "Dmitriy Zaporozhets",
+ "author_email": "dzaporozhets@sphereconsultinginc.com",
+ "created_at": "2012-09-20T11:50:22+03:00"
+ },
+ {
+ "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6",
+ "short_id": "6104942438c",
+ "title": "Sanitize for network graph",
+ "author_name": "randx",
+ "author_email": "dmitriy.zaporozhets@gmail.com",
+ "created_at": "2012-09-20T09:06:12+03:00"
+ }
+]
+```
+
+## Raw blob content
+
+Get the raw file contents for a file.
+
+```
+GET /projects/:id/repository/commits/:sha/blob
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `sha` (required) - The commit or branch name
++ `filepath` (required) - The path the file
+
+Will return the raw file contents.
diff --git a/doc/api/session.md b/doc/api/session.md
new file mode 100644
index 00000000..9fdbeb43
--- /dev/null
+++ b/doc/api/session.md
@@ -0,0 +1,22 @@
+Login to get private token
+
+```
+POST /session
+```
+
+Parameters:
+
++ `email` (required) - The email of user
++ `password` (required) - Valid password
+
+
+```json
+{
+ "id": 1,
+ "email": "john@example.com",
+ "name": "John Smith",
+ "private_token": "dd34asd13as",
+ "created_at": "2012-05-23T08:00:58Z",
+ "blocked": true
+}
+```
diff --git a/doc/api/snippets.md b/doc/api/snippets.md
new file mode 100644
index 00000000..0cd29ce5
--- /dev/null
+++ b/doc/api/snippets.md
@@ -0,0 +1,100 @@
+## List snippets
+
+Not implemented.
+
+## Single snippet
+
+Get a project snippet.
+
+```
+GET /projects/:id/snippets/:snippet_id
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `snippet_id` (required) - The ID of a project's snippet
+
+```json
+{
+ "id": 1,
+ "title": "test",
+ "file_name": "add.rb",
+ "author": {
+ "id": 1,
+ "email": "john@example.com",
+ "name": "John Smith",
+ "blocked": false,
+ "created_at": "2012-05-23T08:00:58Z"
+ },
+ "expires_at": null,
+ "updated_at": "2012-06-28T10:52:04Z",
+ "created_at": "2012-06-28T10:52:04Z"
+}
+```
+
+## Snippet content
+
+Get a raw project snippet.
+
+```
+GET /projects/:id/snippets/:snippet_id/raw
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `snippet_id` (required) - The ID of a project's snippet
+
+## New snippet
+
+Create a new project snippet.
+
+```
+POST /projects/:id/snippets
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `title` (required) - The title of a snippet
++ `file_name` (required) - The name of a snippet file
++ `lifetime` (optional) - The expiration date of a snippet
++ `code` (required) - The content of a snippet
+
+Will return created snippet with status `201 Created` on success, or `404 Not found` on fail.
+
+## Edit snippet
+
+Update an existing project snippet.
+
+```
+PUT /projects/:id/snippets/:snippet_id
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `snippet_id` (required) - The ID of a project's snippet
++ `title` (optional) - The title of a snippet
++ `file_name` (optional) - The name of a snippet file
++ `lifetime` (optional) - The expiration date of a snippet
++ `code` (optional) - The content of a snippet
+
+Will return updated snippet with status `200 OK` on success, or `404 Not found` on fail.
+
+## Delete snippet
+
+Delete existing project snippet.
+
+```
+DELETE /projects/:id/snippets/:snippet_id
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `snippet_id` (required) - The ID of a project's snippet
+
+Status code `200` will be returned on success.
+
diff --git a/doc/api/users.md b/doc/api/users.md
index b9b04dc5..4f806b14 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -88,3 +88,81 @@ GET /user
"theme_id": 1
}
```
+
+## List SSH keys
+
+Get a list of currently authenticated user's SSH keys.
+
+```
+GET /user/keys
+```
+
+```json
+[
+ {
+ "id": 1,
+ "title" : "Public key"
+ "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4
+ 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4
+ soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
+ },
+ {
+ "id": 3,
+ "title" : "Another Public key"
+ "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4
+ 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4
+ soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0="
+ }
+]
+```
+
+## Single SSH key
+
+Get a single key.
+
+```
+GET /user/keys/:id
+```
+
+Parameters:
+
++ `id` (required) - The ID of an SSH key
+
+```json
+{
+ "id": 1,
+ "title" : "Public key"
+ "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4
+ 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4
+ soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0="
+}
+```
+## Add SSH key
+
+Create new key owned by currently authenticated user
+
+```
+POST /user/keys
+```
+
+Parameters:
+
++ `title` (required) - new SSH Key's title
++ `key` (required) - new SSH key
+
+Will return created key with status `201 Created` on success, or `404 Not
+found` on fail.
+
+## Delete SSH key
+
+Delete key owned by currently authenticated user
+
+```
+DELETE /user/keys/:id
+```
+
+Parameters:
+
++ `id` (required) - SSH key ID
+
+Will return `200 OK` on success, or `404 Not Found` on fail.
diff --git a/doc/debian_ubuntu.sh b/doc/debian_ubuntu.sh
deleted file mode 100644
index a0b4710b..00000000
--- a/doc/debian_ubuntu.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/sh
-
-sudo apt-get update
-sudo apt-get upgrade
-
-sudo apt-get install -y git git-core wget curl gcc checkinstall libxml2-dev libxslt-dev sqlite3 libsqlite3-dev libcurl4-openssl-dev libreadline-gplv2-dev libc6-dev libssl-dev libmysql++-dev make build-essential zlib1g-dev libicu-dev redis-server openssh-server python-dev python-pip libyaml-dev postfix
-
-wget http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p194.tar.gz
-tar xfvz ruby-1.9.3-p194.tar.gz
-cd ruby-1.9.3-p194
-./configure
-make
-sudo make install
-
-sudo adduser \
- --system \
- --shell /bin/sh \
- --gecos 'git version control' \
- --group \
- --disabled-password \
- --home /home/git \
- git
-
-sudo adduser --disabled-login --gecos 'gitlab system' gitlab
-
-sudo usermod -a -G git gitlab
-
-sudo -H -u gitlab ssh-keygen -q -N '' -t rsa -f /home/gitlab/.ssh/id_rsa
-
-cd /home/git
-sudo -H -u git git clone git://github.com/gitlabhq/gitolite /home/git/gitolite
-
-sudo -u git -H sh -c "PATH=/home/git/bin:$PATH; /home/git/gitolite/src/gl-system-install"
-sudo cp /home/gitlab/.ssh/id_rsa.pub /home/git/gitlab.pub
-sudo chmod 777 /home/git/gitlab.pub
-
-sudo -u git -H sed -i 's/0077/0007/g' /home/git/share/gitolite/conf/example.gitolite.rc
-sudo -u git -H sh -c "PATH=/home/git/bin:$PATH; gl-setup -q /home/git/gitlab.pub"
-
-sudo chmod -R g+rwX /home/git/repositories/
-sudo chown -R git:git /home/git/repositories/
-
-sudo -u gitlab -H git clone git@localhost:gitolite-admin.git /tmp/gitolite-admin
-sudo rm -rf /tmp/gitolite-admin
diff --git a/doc/development.md b/doc/development.md
new file mode 100644
index 00000000..67bcb8e1
--- /dev/null
+++ b/doc/development.md
@@ -0,0 +1,45 @@
+## Development tips:
+
+### Start application in development mode
+
+#### 1. Via foreman
+
+ bundle exec foreman -p 3000
+
+#### 2. Via gitlab cli
+
+ ./gitlab start
+
+#### 3. Manually
+
+ bundle exec rails s
+ bundle exec rake environment resque:work QUEUE=* VVERBOSE=1
+
+
+### Run tests:
+
+#### 1. Packages
+
+ # ubuntu
+ sudo apt-get install libqt4-dev libqtwebkit-dev
+ sudo apt-get install xvfb
+
+ # Mac
+ brew install qt
+ brew install xvfb
+
+#### 2. DB & seeds
+
+ bundle exec rake db:setup RAILS_ENV=test
+ bundle exec rake db:seed_fu RAILS_ENV=test
+
+### 3. Run Tests
+
+ # All in one
+ bundle exec rake gitlab:test
+
+ # Rspec
+ bundle exec rake spec
+
+ # Spinach
+ bundle exec rake spinach
diff --git a/doc/installation.md b/doc/installation.md
index 2da63ae8..865cde3c 100644
--- a/doc/installation.md
+++ b/doc/installation.md
@@ -20,7 +20,7 @@ You might have some luck using these, but no guarantees:
- MacOS X
- FreeBSD
-Gitlab does **not** run on Windows and we have no plans of making Gitlab compatible.
+GitLab does **not** run on Windows and we have no plans of making GitLab compatible.
## This installation guide created for Debian/Ubuntu and properly tested.
@@ -28,21 +28,21 @@ The installation consists of 6 steps:
1. Install packages / dependencies
2. Install ruby
-3. Install gitolite
-4. Install and configure Gitlab.
+3. Install Gitolite
+4. Install and configure GitLab.
5. Start the web front-end
6. Start a Resque worker (for background processing)
### IMPORTANT
-Please make sure you have followed all the steps below before posting to the mailinglist with installation and configuration questions.
+Please make sure you have followed all the steps below before posting to the mailing list with installation and configuration questions.
-Only create a Github Issue if you want a specific part of this installation guide updated.
+Only create a GitHub Issue if you want a specific part of this installation guide updated.
Also read the [Read this before you submit an issue](https://github.com/gitlabhq/gitlabhq/wiki/Read-this-before-you-submit-an-issue) wiki page.
> - - -
-> First 3 steps can be easily skipped with simply install script:
+> The first 3 steps of this guide can be easily skipped by executing an install script:
>
> # Install curl and sudo
> apt-get install curl sudo
@@ -61,7 +61,11 @@ Also read the [Read this before you submit an issue](https://github.com/gitlabhq
# 1. Install packages
-*Keep in mind that `sudo` is not installed for debian by default. You should install it with as root:* **apt-get update && apt-get upgrade && apt-get install sudo**
+*Keep in mind that `sudo` is not installed on Debian by default. You should install it as root:*
+
+ apt-get update && apt-get upgrade && apt-get install sudo
+
+Now install the required packages:
sudo apt-get update
sudo apt-get upgrade
@@ -71,7 +75,7 @@ Also read the [Read this before you submit an issue](https://github.com/gitlabhq
# If you want to use MySQL:
sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev
-# 2. Install ruby
+# 2. Install Ruby
wget http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p194.tar.gz
tar xfvz ruby-1.9.3-p194.tar.gz
@@ -80,7 +84,7 @@ Also read the [Read this before you submit an issue](https://github.com/gitlabhq
make
sudo make install
-# 3. Install gitolite
+# 3. Install Gitolite
Create user for git:
@@ -93,12 +97,12 @@ Create user for git:
--home /home/git \
git
-Create user for gitlab:
+Create user for GitLab:
# ubuntu/debian
sudo adduser --disabled-login --gecos 'gitlab system' gitlab
-Add your user to git group:
+Add your user to the `git` group:
sudo usermod -a -G git gitlab
@@ -106,20 +110,23 @@ Generate key:
sudo -H -u gitlab ssh-keygen -q -N '' -t rsa -f /home/gitlab/.ssh/id_rsa
-Get gitolite source code:
+Clone GitLab's fork of the Gitolite source code:
cd /home/git
- sudo -H -u git git clone git://github.com/gitlabhq/gitolite /home/git/gitolite
+ sudo -H -u git git clone -b gl-v304 https://github.com/gitlabhq/gitolite.git /home/git/gitolite
Setup:
+ cd /home/git
+ sudo -u git -H mkdir bin
sudo -u git sh -c 'echo -e "PATH=\$PATH:/home/git/bin\nexport PATH" >> /home/git/.profile'
- sudo -u git -H sh -c "PATH=/home/git/bin:$PATH; /home/git/gitolite/src/gl-system-install"
+ sudo -u git sh -c 'gitolite/install -ln /home/git/bin'
+
sudo cp /home/gitlab/.ssh/id_rsa.pub /home/git/gitlab.pub
sudo chmod 0444 /home/git/gitlab.pub
- sudo -u git -H sed -i 's/0077/0007/g' /home/git/share/gitolite/conf/example.gitolite.rc
- sudo -u git -H sh -c "PATH=/home/git/bin:$PATH; gl-setup -q /home/git/gitlab.pub"
+ sudo -u git -H sh -c "PATH=/home/git/bin:$PATH; gitolite setup -pk /home/git/gitlab.pub"
+ sudo -u git -H sed -i 's/0077/0007/g' /home/git/.gitolite.rc
Permissions:
@@ -135,23 +142,30 @@ Permissions:
# if succeed you can remove it
sudo rm -rf /tmp/gitolite-admin
-**IMPORTANT! If you cant clone `gitolite-admin` repository - DONT PROCEED INSTALLATION**
+**IMPORTANT! If you can't clone `gitolite-admin` repository - DO NOT PROCEED WITH INSTALLATION**
+Check the [Trouble Shooting Guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide)
+and ensure you have followed all of the above steps carefully.
-# 4. Install gitlab and configuration. Check status configuration.
+# 4. Clone GitLab source and install prerequisites
sudo gem install charlock_holmes --version '0.6.8'
sudo pip install pygments
sudo gem install bundler
cd /home/gitlab
- sudo -H -u gitlab git clone -b stable git://github.com/gitlabhq/gitlabhq.git gitlab
- cd gitlab
- sudo -u gitlab mkdir tmp
+ # Get gitlab code. Use this for stable setup
+ sudo -H -u gitlab git clone -b stable https://github.com/gitlabhq/gitlabhq.git gitlab
+
+ # Skip this for stable setup.
+ # Master branch (recent changes, less stable)
+ sudo -H -u gitlab git clone -b master https://github.com/gitlabhq/gitlabhq.git gitlab
+
+ cd gitlab
# Rename config files
sudo -u gitlab cp config/gitlab.yml.example config/gitlab.yml
-#### Select db you want to use
+#### Select the database you want to use
# SQLite
sudo -u gitlab cp config/database.yml.sqlite config/database.yml
@@ -163,7 +177,7 @@ Permissions:
# Login to MySQL
$ mysql -u root -p
- # Create the gitlabhq production database
+ # Create the GitLab production database
mysql> CREATE DATABASE IF NOT EXISTS `gitlabhq_production` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`;
# Create the MySQL User change $password to a real password
@@ -179,14 +193,16 @@ Permissions:
sudo -u gitlab -H bundle install --without development test --deployment
-#### Setup DB
+#### Setup database
sudo -u gitlab bundle exec rake gitlab:app:setup RAILS_ENV=production
-#### Setup gitlab hooks
+#### Setup GitLab hooks
- sudo cp ./lib/hooks/post-receive /home/git/share/gitolite/hooks/common/post-receive
- sudo chown git:git /home/git/share/gitolite/hooks/common/post-receive
+ sudo cp ./lib/hooks/post-receive /home/git/.gitolite/hooks/common/post-receive
+ sudo chown git:git /home/git/.gitolite/hooks/common/post-receive
+
+#### Check application status
Checking status:
@@ -208,9 +224,9 @@ Checking status:
UMASK for .gitolite.rc is 0007? ............YES
/home/git/share/gitolite/hooks/common/post-receive exists? ............YES
-If you got all YES - congrats! You can go to next step.
+If you got all YES - congratulations! You can go to the next step.
-# 5. Server up
+# 5. Start the web server
Application can be started with next command:
@@ -225,33 +241,41 @@ You can login via web using admin generated with setup:
admin@local.host
5iveL!fe
-# 6. Run resque process (for processing queue).
+# 6. Run Resque process (for processing job queue).
# Manually
sudo -u gitlab bundle exec rake environment resque:work QUEUE=* RAILS_ENV=production BACKGROUND=yes
- # Gitlab start script
+ # GitLab start script
sudo -u gitlab ./resque.sh
# if you run this as root /home/gitlab/gitlab/tmp/pids/resque_worker.pid will be owned by root
# causing the resque worker not to start via init script on next boot/service restart
+## Customizing Resque's Redis connection
+
+If you'd like Resque to connect to a Redis server on a non-standard port or on
+a different host, you can configure its connection string in the
+**config/resque.yml** file:
+
+ production: redis.example.com:6379
+
**Ok - we have a working application now. **
-**But keep going - there are some thing that should be done **
+**But keep going - there are some things that should be done **
# Nginx && Unicorn
-### Install Nginx
-
- sudo apt-get install nginx
-
-## Unicorn
+## 1. Unicorn
cd /home/gitlab/gitlab
- sudo -u gitlab cp config/unicorn.rb.orig config/unicorn.rb
+ sudo -u gitlab cp config/unicorn.rb.example config/unicorn.rb
sudo -u gitlab bundle exec unicorn_rails -c config/unicorn.rb -E production -D
-Add GitLab to nginx sites & change with your host specific settings
+## 2. Nginx
+ # Install first
+ sudo apt-get install nginx
+
+ # Add GitLab to nginx sites & change with your host specific settings
sudo wget https://raw.github.com/gitlabhq/gitlab-recipes/master/nginx/gitlab -P /etc/nginx/sites-available/
sudo ln -s /etc/nginx/sites-available/gitlab /etc/nginx/sites-enabled/gitlab
@@ -260,22 +284,20 @@ Add GitLab to nginx sites & change with your host specific settings
# of the host serving GitLab.
sudo vim /etc/nginx/sites-enabled/gitlab
-Restart nginx:
-
+ # Restart nginx:
/etc/init.d/nginx restart
+## 3. Init script
+
Create init script in /etc/init.d/gitlab:
sudo wget https://raw.github.com/gitlabhq/gitlab-recipes/master/init.d/gitlab -P /etc/init.d/
-
-Adding permission:
-
sudo chmod +x /etc/init.d/gitlab
-Gitlab autostart:
+GitLab autostart:
sudo update-rc.d gitlab defaults
-Now you can start/restart/stop gitlab like:
+Now you can start/restart/stop GitLab like:
sudo /etc/init.d/gitlab restart
diff --git a/features/dashboard/dashboard.feature b/features/dashboard/dashboard.feature
index a8c2205c..9756bc7f 100644
--- a/features/dashboard/dashboard.feature
+++ b/features/dashboard/dashboard.feature
@@ -1,9 +1,9 @@
Feature: Dashboard
- Background:
- Given I signin as a user
+ Background:
+ Given I sign in as a user
And I own project "Shop"
And project "Shop" has push event
- And I visit dashboard page
+ And I visit dashboard page
Scenario: I should see projects list
Then I should see "New Project" link
@@ -15,4 +15,13 @@ Feature: Dashboard
And I click "Create Merge Request" link
Then I see prefilled new Merge Request page
+ Scenario: I should see User joined Project event
+ Given user with name "John Doe" joined project "Shop"
+ When I visit dashboard page
+ Then I should see "John Doe joined project Shop" event
+ Scenario: I should see User left Project event
+ Given user with name "John Doe" joined project "Shop"
+ And user with name "John Doe" left project "Shop"
+ When I visit dashboard page
+ Then I should see "John Doe left project Shop" event
diff --git a/features/dashboard/issues.feature b/features/dashboard/issues.feature
index c3361bb3..895b89aa 100644
--- a/features/dashboard/issues.feature
+++ b/features/dashboard/issues.feature
@@ -1,8 +1,8 @@
Feature: Dashboard Issues
- Background:
- Given I signin as a user
+ Background:
+ Given I sign in as a user
And I have assigned issues
- And I visit dashboard issues page
+ And I visit dashboard issues page
Scenario: I should see issues list
Then I should see issues assigned to me
diff --git a/features/dashboard/merge_requests.feature b/features/dashboard/merge_requests.feature
index 90b8749c..cad65b0d 100644
--- a/features/dashboard/merge_requests.feature
+++ b/features/dashboard/merge_requests.feature
@@ -1,8 +1,8 @@
-Feature: Dashboard MR
- Background:
- Given I signin as a user
+Feature: Dashboard Merge Requests
+ Background:
+ Given I sign in as a user
And I have authored merge requests
- And I visit dashboard merge requests page
+ And I visit dashboard merge requests page
Scenario: I should see projects list
Then I should see my merge requests
diff --git a/features/dashboard/search.feature b/features/dashboard/search.feature
index f053fe86..91d870f4 100644
--- a/features/dashboard/search.feature
+++ b/features/dashboard/search.feature
@@ -1,11 +1,9 @@
Feature: Dashboard Search
- Background:
- Given I signin as a user
+ Background:
+ Given I sign in as a user
And I own project "Shop"
- And I visit dashboard search page
+ And I visit dashboard search page
- Scenario: I should see project i'm looking for
+ Scenario: I should see project I am looking for
Given I search for "Sho"
Then I should see "Shop" project link
-
-
diff --git a/features/profile/profile.feature b/features/profile/profile.feature
index afda4b55..134cabb5 100644
--- a/features/profile/profile.feature
+++ b/features/profile/profile.feature
@@ -1,6 +1,6 @@
Feature: Profile
- Background:
- Given I signin as a user
+ Background:
+ Given I sign in as a user
Scenario: I look at my profile
Given I visit profile page
@@ -12,11 +12,11 @@ Feature: Profile
And I should see new contact info
Scenario: I change my password
- Given I visit profile password page
+ Given I visit profile account page
Then I change my password
And I should be redirected to sign in page
Scenario: I reset my token
- Given I visit profile token page
+ Given I visit profile account page
Then I reset my token
And I should see new token
diff --git a/features/profile/ssh_keys.feature b/features/profile/ssh_keys.feature
index c3a92f30..018d124e 100644
--- a/features/profile/ssh_keys.feature
+++ b/features/profile/ssh_keys.feature
@@ -1,13 +1,10 @@
-Feature: SSH Keys
- Background:
- Given I signin as a user
- And I have ssh keys:
- | title |
- | Work |
- | Home |
+Feature: Profile SSH Keys
+ Background:
+ Given I sign in as a user
+ And I have ssh key "ssh-rsa Work"
And I visit profile keys page
- Scenario: I should see SSH keys
+ Scenario: I should see ssh keys
Then I should see my ssh keys
Scenario: Add new ssh key
diff --git a/features/projects/commits/branches.feature b/features/project/commits/branches.feature
similarity index 66%
rename from features/projects/commits/branches.feature
rename to features/project/commits/branches.feature
index 74575c51..4fa4dc26 100644
--- a/features/projects/commits/branches.feature
+++ b/features/project/commits/branches.feature
@@ -1,6 +1,6 @@
-Feature: Browse branches
- Background:
- Given I signin as a user
+Feature: Project Browse branches
+ Background:
+ Given I sign in as a user
And I own project "Shop"
And project "Shop" has protected branches
Given I visit project branches page
@@ -16,8 +16,11 @@ Feature: Browse branches
Given I click link "Protected"
Then I should see "Shop" protected branches list
- Scenario: I can download project by branch
+ # @wip
+ # Scenario: I can download project by branch
- Scenario: I can view protected branches
+ # @wip
+ # Scenario: I can view protected branches
- Scenario: I can manage protected branches
+ # @wip
+ # Scenario: I can manage protected branches
diff --git a/features/projects/commits/commit_comments.feature b/features/project/commits/commit_comments.feature
similarity index 72%
rename from features/projects/commits/commit_comments.feature
rename to features/project/commits/commit_comments.feature
index 9bd56d29..5acf541a 100644
--- a/features/projects/commits/commit_comments.feature
+++ b/features/project/commits/commit_comments.feature
@@ -1,6 +1,6 @@
-Feature: Comment commit
- Background:
- Given I signin as a user
+Feature: Project Comment commit
+ Background:
+ Given I sign in as a user
And I own project "Shop"
Given I visit project commit page
diff --git a/features/projects/commits/commits.feature b/features/project/commits/commits.feature
similarity index 82%
rename from features/projects/commits/commits.feature
rename to features/project/commits/commits.feature
index 69d39d78..53de6e6a 100644
--- a/features/projects/commits/commits.feature
+++ b/features/project/commits/commits.feature
@@ -1,6 +1,6 @@
-Feature: Browse commits
- Background:
- Given I signin as a user
+Feature: Project Browse commits
+ Background:
+ Given I sign in as a user
And I own project "Shop"
Given I visit project commits page
@@ -18,5 +18,4 @@ Feature: Browse commits
Scenario: I compare refs
Given I visit compare refs page
And I fill compare fields with refs
- And I see compared refs
-
+ And I see compared refs
diff --git a/features/projects/commits/tags.feature b/features/project/commits/tags.feature
similarity index 53%
rename from features/projects/commits/tags.feature
rename to features/project/commits/tags.feature
index f7899fc3..1ac0f8bf 100644
--- a/features/projects/commits/tags.feature
+++ b/features/project/commits/tags.feature
@@ -1,10 +1,11 @@
-Feature: Browse tags
- Background:
- Given I signin as a user
+Feature: Project Browse tags
+ Background:
+ Given I sign in as a user
And I own project "Shop"
Given I visit project tags page
Scenario: I can see all git tags
Then I should see "Shop" all tags list
- Scenario: I can download project by tag
+ # @wip
+ # Scenario: I can download project by tag
diff --git a/features/projects/create_project.feature b/features/project/create_project.feature
similarity index 91%
rename from features/projects/create_project.feature
rename to features/project/create_project.feature
index 42d25b3f..b7cdfdb8 100644
--- a/features/projects/create_project.feature
+++ b/features/project/create_project.feature
@@ -4,7 +4,7 @@ Feature: Create Project
Should be able to create a new one
Scenario: User create a project
- Given I signin as a user
+ Given I sign in as a user
When I visit new project page
And fill project form with valid data
Then I should see project page
diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature
new file mode 100644
index 00000000..596e8bd7
--- /dev/null
+++ b/features/project/issues/issues.feature
@@ -0,0 +1,81 @@
+Feature: Project Issues
+ Background:
+ Given I sign in as a user
+ And I own project "Shop"
+ And project "Shop" have "Release 0.4" open issue
+ And project "Shop" have "Release 0.3" closed issue
+ And I visit project "Shop" issues page
+
+ Scenario: I should see open issues
+ Given I should see "Release 0.4" in issues
+ And I should not see "Release 0.3" in issues
+
+ Scenario: I should see closed issues
+ Given I click link "Closed"
+ Then I should see "Release 0.3" in issues
+ And I should not see "Release 0.4" in issues
+
+ Scenario: I should see all issues
+ Given I click link "All"
+ Then I should see "Release 0.3" in issues
+ And I should see "Release 0.4" in issues
+
+ Scenario: I visit issue page
+ Given I click link "Release 0.4"
+ Then I should see issue "Release 0.4"
+
+ @javascript
+ Scenario: I submit new unassigned issue
+ Given I click link "New Issue"
+ And I submit new issue "500 error on profile"
+ Given I click link "500 error on profile"
+ Then I should see issue "500 error on profile"
+
+ @javascript
+ Scenario: I comment issue
+ Given I visit issue page "Release 0.4"
+ And I leave a comment like "XML attached"
+ Then I should see comment "XML attached"
+
+ @javascript
+ Scenario: I search issue
+ Given I fill in issue search with "Release"
+ Then I should see "Release 0.4" in issues
+ And I should not see "Release 0.3" in issues
+
+ @javascript
+ Scenario: I search issue that not exist
+ Given I fill in issue search with "Bug"
+ Then I should not see "Release 0.4" in issues
+ And I should not see "Release 0.3" in issues
+
+
+ @javascript
+ Scenario: I search all issues
+ Given I click link "All"
+ And I fill in issue search with "0.3"
+ Then I should see "Release 0.3" in issues
+ And I should not see "Release 0.4" in issues
+
+ @javascript
+ Scenario: I clear search
+ Given I click link "All"
+ And I fill in issue search with "Something"
+ And I fill in issue search with ""
+ Then I should see "Release 0.4" in issues
+ And I should see "Release 0.3" in issues
+
+ @javascript
+ Scenario: I create Issue with pre-selected milestone
+ Given project "Shop" has milestone "v2.2"
+ And project "Shop" has milestone "v3.0"
+ And I visit project "Shop" issues page
+ When I select milestone "v3.0"
+ And I click link "New Issue"
+ Then I should see selected milestone with title "v3.0"
+
+ @javascript
+ Scenario: I create Issue with pre-selected assignee
+ When I select first assignee from "Shop" project
+ And I click link "New Issue"
+ Then I should see first assignee from "Shop" as selected assignee
diff --git a/features/project/issues/labels.feature b/features/project/issues/labels.feature
new file mode 100644
index 00000000..e601a41b
--- /dev/null
+++ b/features/project/issues/labels.feature
@@ -0,0 +1,10 @@
+Feature: Project Labels
+ Background:
+ Given I sign in as a user
+ And I own project "Shop"
+ And project "Shop" have issues tags: "bug", "feature"
+ Given I visit project "Shop" labels page
+
+ Scenario: I should see active milestones
+ Then I should see label "bug"
+ And I should see label "feature"
diff --git a/features/projects/issues/milestones.feature b/features/project/issues/milestones.feature
similarity index 79%
rename from features/projects/issues/milestones.feature
rename to features/project/issues/milestones.feature
index d78096a4..a57f67d6 100644
--- a/features/projects/issues/milestones.feature
+++ b/features/project/issues/milestones.feature
@@ -1,9 +1,9 @@
-Feature: Milestones
+Feature: Project Milestones
Background:
- Given I signin as a user
+ Given I sign in as a user
And I own project "Shop"
And project "Shop" has milestone "v2.2"
- Given I visit project "Shop" milestones page
+ Given I visit project "Shop" milestones page
Scenario: I should see active milestones
Then I should see milestone "v2.2"
diff --git a/features/projects/merge_requests.feature b/features/project/merge_requests.feature
similarity index 92%
rename from features/projects/merge_requests.feature
rename to features/project/merge_requests.feature
index 54b6ccde..80f00986 100644
--- a/features/projects/merge_requests.feature
+++ b/features/project/merge_requests.feature
@@ -1,10 +1,10 @@
-Feature: Merge Requests
+Feature: Project Merge Requests
Background:
- Given I signin as a user
+ Given I sign in as a user
And I own project "Shop"
And project "Shop" have "Bug NS-04" open merge request
And project "Shop" have "Feature NS-03" closed merge request
- And I visit project "Shop" merge requests page
+ And I visit project "Shop" merge requests page
Scenario: I should see open merge requests
Then I should see "Bug NS-04" in merge requests
diff --git a/features/projects/network.feature b/features/project/network.feature
similarity index 81%
rename from features/projects/network.feature
rename to features/project/network.feature
index 61c05eb3..31ce5ad3 100644
--- a/features/projects/network.feature
+++ b/features/project/network.feature
@@ -1,10 +1,9 @@
-@javascript
Feature: Project Network Graph
-
Background:
- Given I signin as a user
+ Given I sign in as a user
And I own project "Shop"
And I visit project "Shop" network page
+ @javascript
Scenario: I should see project network
Then page should have network graph
diff --git a/features/project/project.feature b/features/project/project.feature
new file mode 100644
index 00000000..1c9f201d
--- /dev/null
+++ b/features/project/project.feature
@@ -0,0 +1,14 @@
+Feature: Projects
+ Background:
+ Given I signin as a user
+ And I own project "Shop"
+ And I visit project "Shop" page
+
+ # @wip
+ # Scenario: I should see project activity
+
+ # @wip
+ # Scenario: I edit project
+
+ # @wip
+ # Scenario: I visit attachments
diff --git a/features/projects/source/browse_files.feature b/features/project/source/browse_files.feature
similarity index 71%
rename from features/projects/source/browse_files.feature
rename to features/project/source/browse_files.feature
index 04aebc19..b12b0ee3 100644
--- a/features/projects/source/browse_files.feature
+++ b/features/project/source/browse_files.feature
@@ -1,6 +1,6 @@
-Feature: Browse git repo
- Background:
- Given I signin as a user
+Feature: Project Browse files
+ Background:
+ Given I sign in as a user
And I own project "Shop"
Given I visit project source page
@@ -12,12 +12,10 @@ Feature: Browse git repo
Then I should see files from repository for "8470d70"
Scenario: I browse file content
- Given I click on file from repo
+ Given I click on "Gemfile" file in repo
Then I should see it content
Scenario: I browse raw file
- Given I visit blob file from repo
- And I click on raw button
+ Given I visit blob file from repo
+ And I click link "raw"
Then I should see raw file content
-
-
diff --git a/features/project/source/git_blame.feature b/features/project/source/git_blame.feature
new file mode 100644
index 00000000..93ed20a8
--- /dev/null
+++ b/features/project/source/git_blame.feature
@@ -0,0 +1,10 @@
+Feature: Project Browse git repo
+ Background:
+ Given I sign in as a user
+ And I own project "Shop"
+ Given I visit project source page
+
+ Scenario: I blame file
+ Given I click on "Gemfile" file in repo
+ And I click blame button
+ Then I should see git file blame
diff --git a/features/projects/team_management.feature b/features/project/team_management.feature
similarity index 78%
rename from features/projects/team_management.feature
rename to features/project/team_management.feature
index b5b485e2..ae0c459f 100644
--- a/features/projects/team_management.feature
+++ b/features/project/team_management.feature
@@ -1,11 +1,11 @@
Feature: Project Team management
- Background:
- Given I signin as a user
+ Background:
+ Given I sign in as a user
And I own project "Shop"
- And gitlab user "Mike"
- And gitlab user "Sam"
+ And gitlab user "Mike"
+ And gitlab user "Sam"
And "Sam" is "Shop" developer
- And I visit project "Shop" team page
+ And I visit project "Shop" team page
Scenario: See all team members
Then I should be able to see myself in team
@@ -20,7 +20,7 @@ Feature: Project Team management
Scenario: Update user access
Given I should see "Sam" in team list as "Developer"
And I change "Sam" role to "Reporter"
- Then I visit project "Shop" team page
+ Then I visit project "Shop" team page
And I should see "Sam" in team list as "Reporter"
Scenario: View team member profile
@@ -30,6 +30,5 @@ Feature: Project Team management
Scenario: Cancel team member
Given I click link "Sam"
And I click link "Remove from team"
- Then I visit project "Shop" team page
+ Then I visit project "Shop" team page
And I should not see "Sam" in team list
-
diff --git a/features/projects/wall.feature b/features/project/wall.feature
similarity index 63%
rename from features/projects/wall.feature
rename to features/project/wall.feature
index ed675e2c..c38d046a 100644
--- a/features/projects/wall.feature
+++ b/features/project/wall.feature
@@ -1,17 +1,16 @@
-@javascript
Feature: Project Wall
In order to use Project Wall
- A user
- Should be able to read & write messages
+ A user should be able to read and write messages
Background:
- Given I signin as a user
+ Given I sign in as a user
And I own project "Shop"
- And I visit project "Shop" wall page
+ And I visit project "Shop" wall page
+ @javascript
Scenario: Write comment
Given I write new comment "my special test message"
Then I should see project wall note "my special test message"
- Then I visit project "Shop" wall page
+ Then I visit project "Shop" wall page
And I should see project wall note "my special test message"
diff --git a/features/projects/wiki.feature b/features/project/wiki.feature
similarity index 83%
rename from features/projects/wiki.feature
rename to features/project/wiki.feature
index 4441ada2..51370565 100644
--- a/features/projects/wiki.feature
+++ b/features/project/wiki.feature
@@ -1,6 +1,6 @@
-Feature: Wiki
- Background:
- Given I signin as a user
+Feature: Project Wiki
+ Background:
+ Given I sign in as a user
And I own project "Shop"
Given I visit project wiki page
diff --git a/features/projects/issues/issues.feature b/features/projects/issues/issues.feature
deleted file mode 100644
index 180710cf..00000000
--- a/features/projects/issues/issues.feature
+++ /dev/null
@@ -1,38 +0,0 @@
-Feature: Issues
- Background:
- Given I signin as a user
- And I own project "Shop"
- And project "Shop" have "Release 0.4" open issue
- And project "Shop" have "Release 0.3" closed issue
- And I visit project "Shop" issues page
-
- Scenario: I should see open issues
- Given I should see "Release 0.4" in issues
- And I should not see "Release 0.3" in issues
-
- Scenario: I should see closed issues
- Given I click link "Closed"
- Then I should see "Release 0.3" in issues
- And I should not see "Release 0.4" in issues
-
- Scenario: I should see all issues
- Given I click link "All"
- Then I should see "Release 0.3" in issues
- And I should see "Release 0.4" in issues
-
- Scenario: I visit issue page
- Given I click link "Release 0.4"
- Then I should see issue "Release 0.4"
-
- @javascript
- Scenario: I submit new unassigned issue
- Given I click link "New Issue"
- And I submit new issue "500 error on profile"
- Given I click link "500 error on profile"
- Then I should see issue "500 error on profile"
-
- @javascript
- Scenario: I comment issue
- Given I visit issue page "Release 0.4"
- And I leave a comment like "XML attached"
- Then I should see comment "XML attached"
diff --git a/features/projects/project.feature b/features/projects/project.feature
deleted file mode 100644
index 895a928f..00000000
--- a/features/projects/project.feature
+++ /dev/null
@@ -1,11 +0,0 @@
-Feature: Project
- Background:
- Given I signin as a user
- And I own project "Shop"
- And I visit project "Shop" page
-
- Scenario: I should see project activity
-
- Scenario: I edit project
-
- Scenario: I visit attachments
diff --git a/features/projects/snippets.feature b/features/projects/snippets.feature
deleted file mode 100644
index e69de29b..00000000
diff --git a/features/projects/source/git_blame.feature b/features/projects/source/git_blame.feature
deleted file mode 100644
index 6aa6be47..00000000
--- a/features/projects/source/git_blame.feature
+++ /dev/null
@@ -1,10 +0,0 @@
-Feature: Browse git repo
- Background:
- Given I signin as a user
- And I own project "Shop"
- Given I visit project source page
-
- Scenario: I blame file
- Given I click on file from repo
- And I click blame button
- Then I should see git file blame
diff --git a/features/projects/web_hooks.feature b/features/projects/web_hooks.feature
deleted file mode 100644
index e69de29b..00000000
diff --git a/features/step_definitions/dashboard_steps.rb b/features/step_definitions/dashboard_steps.rb
deleted file mode 100644
index 1eec7619..00000000
--- a/features/step_definitions/dashboard_steps.rb
+++ /dev/null
@@ -1,127 +0,0 @@
-Given /^I visit dashboard page$/ do
- visit dashboard_path
-end
-
-Then /^I should see "(.*?)" link$/ do |arg1|
- page.should have_link(arg1)
-end
-
-Then /^I should see "(.*?)" project link$/ do |arg1|
- page.should have_link(arg1)
-end
-
-Then /^I should see project "(.*?)" activity feed$/ do |arg1|
- project = Project.find_by_name(arg1)
- page.should have_content "#{@user.name} pushed new branch new_design at #{project.name}"
-end
-
-Given /^project "(.*?)" has push event$/ do |arg1|
- @project = Project.find_by_name(arg1)
-
- data = {
- :before => "0000000000000000000000000000000000000000",
- :after => "0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e",
- :ref => "refs/heads/new_design",
- :user_id => @user.id,
- :user_name => @user.name,
- :repository => {
- :name => @project.name,
- :url => "localhost/rubinius",
- :description => "",
- :homepage => "localhost/rubinius",
- :private => true
- }
- }
-
- @event = Event.create(
- :project => @project,
- :action => Event::Pushed,
- :data => data,
- :author_id => @user.id
- )
-end
-
-Then /^I should see last push widget$/ do
- page.should have_content "Your pushed to branch new_design"
- page.should have_link "Create Merge Request"
-end
-
-Then /^I click "(.*?)" link$/ do |arg1|
- click_link arg1 #Create Merge Request"
-end
-
-Then /^I see prefilled new Merge Request page$/ do
- current_path.should == new_project_merge_request_path(@project)
- find("#merge_request_source_branch").value.should == "new_design"
- find("#merge_request_target_branch").value.should == "master"
- find("#merge_request_title").value.should == "New Design"
-end
-
-Given /^I visit dashboard search page$/ do
- visit search_path
-end
-
-Given /^I search for "(.*?)"$/ do |arg1|
- fill_in "dashboard_search", :with => arg1
- click_button "Search"
-end
-
-Given /^I visit dashboard issues page$/ do
- visit dashboard_issues_path
-end
-
-Then /^I should see issues assigned to me$/ do
- issues = @user.issues
- issues.each do |issue|
- page.should have_content(issue.title[0..10])
- page.should have_content(issue.project.name)
- end
-end
-
-Given /^I visit dashboard merge requests page$/ do
- visit dashboard_merge_requests_path
-end
-
-Then /^I should see my merge requests$/ do
- merge_requests = @user.merge_requests
- merge_requests.each do |mr|
- page.should have_content(mr.title[0..10])
- page.should have_content(mr.project.name)
- end
-end
-
-Given /^I have assigned issues$/ do
- project = Factory :project
- project.add_access(@user, :read, :write)
-
- issue1 = Factory :issue,
- :author => @user,
- :assignee => @user,
- :project => project
-
- issue2 = Factory :issue,
- :author => @user,
- :assignee => @user,
- :project => project
-end
-
-Given /^I have authored merge requests$/ do
- project1 = Factory :project,
- :path => "project1",
- :code => "gitlabhq_1"
-
- project2 = Factory :project,
- :path => "project2",
- :code => "gitlabhq_2"
-
- project1.add_access(@user, :read, :write)
- project2.add_access(@user, :read, :write)
-
- merge_request1 = Factory :merge_request,
- :author => @user,
- :project => project1
-
- merge_request2 = Factory :merge_request,
- :author => @user,
- :project => project2
-end
diff --git a/features/step_definitions/profile/profile_keys_steps.rb b/features/step_definitions/profile/profile_keys_steps.rb
deleted file mode 100644
index 5ab7e048..00000000
--- a/features/step_definitions/profile/profile_keys_steps.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-Given /^I visit profile keys page$/ do
- visit keys_path
-end
-
-Then /^I should see my ssh keys$/ do
- @user.keys.each do |key|
- page.should have_content(key.title)
- end
-end
-
-Given /^I have ssh keys:$/ do |table|
- table.hashes.each do |row|
- Factory :key, :user => @user, :title => row[:title], :key => "jfKLJDFKSFJSHFJ#{row[:title]}"
- end
-end
-
-Given /^I submit new ssh key "(.*?)"$/ do |arg1|
- fill_in "key_title", :with => arg1
- fill_in "key_key", :with => "publickey234="
- click_button "Save"
-end
-
-Then /^I should see new ssh key "(.*?)"$/ do |arg1|
- key = Key.find_by_title(arg1)
- page.should have_content(key.title)
- page.should have_content(key.key)
- current_path.should == key_path(key)
-end
-
-Then /^I should not see "(.*?)" ssh key$/ do |arg1|
- within "#keys-table" do
- page.should_not have_content(arg1)
- end
-end
diff --git a/features/step_definitions/profile/profile_steps.rb b/features/step_definitions/profile/profile_steps.rb
deleted file mode 100644
index 4661139c..00000000
--- a/features/step_definitions/profile/profile_steps.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-Given /^I visit profile page$/ do
- visit profile_path
-end
-
-Then /^I should see my profile info$/ do
- page.should have_content "Profile"
- page.should have_content @user.name
- page.should have_content @user.email
-end
-
-Given /^I visit profile password page$/ do
- visit profile_password_path
-end
-
-Then /^I change my password$/ do
- fill_in "user_password", :with => "222333"
- fill_in "user_password_confirmation", :with => "222333"
- click_button "Save"
-end
-
-Then /^I should be redirected to sign in page$/ do
- current_path.should == new_user_session_path
-end
-
-Given /^I visit profile token page$/ do
- visit profile_token_path
-end
-
-Then /^I reset my token$/ do
- @old_token = @user.private_token
- click_button "Reset"
-end
-
-Then /^I should see new token$/ do
- find("#token").value.should_not == @old_token
- find("#token").value.should == @user.reload.private_token
-end
-
-Then /^I change my contact info$/ do
- fill_in "user_skype", :with => "testskype"
- fill_in "user_linkedin", :with => "testlinkedin"
- fill_in "user_twitter", :with => "testtwitter"
- click_button "Save"
- @user.reload
-end
-
-Then /^I should see new contact info$/ do
- @user.skype.should == 'testskype'
- @user.linkedin.should == 'testlinkedin'
- @user.twitter.should == 'testtwitter'
-end
diff --git a/features/step_definitions/project/browse_code_steps.rb b/features/step_definitions/project/browse_code_steps.rb
deleted file mode 100644
index 7f9001bb..00000000
--- a/features/step_definitions/project/browse_code_steps.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-Given /^I visit project source page$/ do
- visit tree_project_ref_path(@project, @project.root_ref)
-end
-
-Then /^I should see files from repository$/ do
- page.should have_content("app")
- page.should have_content("History")
- page.should have_content("Gemfile")
-end
-
-Given /^I visit project source page for "(.*?)"$/ do |arg1|
- visit tree_project_ref_path(@project, arg1)
-end
-
-Then /^I should see files from repository for "(.*?)"$/ do |arg1|
- current_path.should == tree_project_ref_path(@project, arg1)
- page.should have_content("app")
- page.should have_content("History")
- page.should have_content("Gemfile")
-end
-
-Given /^I click on file from repo$/ do
- click_link "Gemfile"
-end
-
-Then /^I should see it content$/ do
- page.should have_content("rubygems.org")
-end
-
-Given /^I click on raw button$/ do
- click_link "raw"
-end
-
-Given /^I visit blob file from repo$/ do
- visit tree_project_ref_path(@project, ValidCommit::ID, :path => ValidCommit::BLOB_FILE_PATH)
-end
-
-Then /^I should see raw file content$/ do
- page.source.should == ValidCommit::BLOB_FILE
-end
-
-Given /^I click blame button$/ do
- click_link "blame"
-end
-
-Then /^I should see git file blame$/ do
- page.should have_content("rubygems.org")
- page.should have_content("Dmitriy Zaporozhets")
- page.should have_content("bc3735004cb Moving to rails 3.2")
-end
diff --git a/features/step_definitions/project/project_commits_steps.rb b/features/step_definitions/project/project_commits_steps.rb
deleted file mode 100644
index 35fcb4d1..00000000
--- a/features/step_definitions/project/project_commits_steps.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-Given /^I visit project commits page$/ do
- visit project_commits_path(@project)
-end
-
-Then /^I see project commits$/ do
- current_path.should == project_commits_path(@project)
-
- commit = @project.commit
- page.should have_content(@project.name)
- page.should have_content(commit.message)
- page.should have_content(commit.id.to_s[0..5])
-end
-
-Given /^I click atom feed link$/ do
- click_link "Feed"
-end
-
-Then /^I see commits atom feed$/ do
- commit = CommitDecorator.decorate(@project.commit)
- page.response_headers['Content-Type'].should have_content("application/atom+xml")
- page.body.should have_selector("title", :text => "Recent commits to #{@project.name}")
- page.body.should have_selector("author email", :text => commit.author_email)
- page.body.should have_selector("entry summary", :text => commit.description)
-end
-
-Given /^I click on commit link$/ do
- visit project_commit_path(@project, ValidCommit::ID)
-end
-
-Then /^I see commit info$/ do
- page.should have_content ValidCommit::MESSAGE
- page.should have_content "Showing 1 changed file"
-end
-
-Given /^I visit compare refs page$/ do
- visit compare_project_commits_path(@project)
-end
-
-Given /^I fill compare fields with refs$/ do
- fill_in "from", :with => "master"
- fill_in "to", :with => "stable"
- click_button "Compare"
-end
-
-Given /^I see compared refs$/ do
- page.should have_content "Commits (27)"
- page.should have_content "Compare View"
- page.should have_content "Showing 73 changed files"
-end
-
-Given /^I visit project branches page$/ do
- visit branches_project_repository_path(@project)
-end
-
-Given /^I visit project commit page$/ do
- visit project_commit_path(@project, ValidCommit::ID)
-end
-
-Given /^I visit project tags page$/ do
- visit tags_project_repository_path(@project)
-end
-
-Then /^I should see "(.*?)" recent branches list$/ do |arg1|
- page.should have_content("Branches")
- page.should have_content("master")
-end
-
-Then /^I should see "(.*?)" all branches list$/ do |arg1|
- page.should have_content("Branches")
- page.should have_content("master")
-end
-
-Then /^I should see "(.*?)" all tags list$/ do |arg1|
- page.should have_content("Tags")
- page.should have_content("v1.2.1")
-end
-
-Then /^I should see "(.*?)" protected branches list$/ do |arg1|
- within "table" do
- page.should have_content "stable"
- page.should_not have_content "master"
- end
-end
-
-Given /^project "(.*?)" has protected branches$/ do |arg1|
- project = Project.find_by_name(arg1)
- project.protected_branches.create(:name => "stable")
-end
diff --git a/features/step_definitions/project/project_issues_steps.rb b/features/step_definitions/project/project_issues_steps.rb
deleted file mode 100644
index 00a1721f..00000000
--- a/features/step_definitions/project/project_issues_steps.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-Given /^project "(.*?)" have "(.*?)" open issue$/ do |arg1, arg2|
- project = Project.find_by_name(arg1)
- Factory.create(:issue, :title => arg2, :project => project, :author => project.users.first)
-end
-
-Given /^project "(.*?)" have "(.*?)" closed issue$/ do |arg1, arg2|
- project = Project.find_by_name(arg1)
- Factory.create(:issue, :title => arg2, :project => project, :author => project.users.first, :closed => true)
-end
-
-Given /^I visit project "(.*?)" issues page$/ do |arg1|
- visit project_issues_path(Project.find_by_name(arg1))
-end
-
-Given /^I should see "(.*?)" in issues$/ do |arg1|
- page.should have_content arg1
-end
-
-Given /^I should not see "(.*?)" in issues$/ do |arg1|
- page.should_not have_content arg1
-end
-
-Then /^I should see issue "(.*?)"$/ do |arg1|
- issue = Issue.find_by_title(arg1)
- page.should have_content issue.title
- page.should have_content issue.author_name
- page.should have_content issue.project.name
-end
-
-Given /^I visit issue page "(.*?)"$/ do |arg1|
- issue = Issue.find_by_title(arg1)
- visit project_issue_path(issue.project, issue)
-end
-
-Given /^I submit new issue "(.*?)"$/ do |arg1|
- fill_in "issue_title", :with => arg1
- click_button "Submit new issue"
-end
diff --git a/features/step_definitions/project/project_merge_requests_steps.rb b/features/step_definitions/project/project_merge_requests_steps.rb
deleted file mode 100644
index 2bdb967d..00000000
--- a/features/step_definitions/project/project_merge_requests_steps.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-Given /^project "(.*?)" have "(.*?)" open merge request$/ do |arg1, arg2|
- project = Project.find_by_name(arg1)
- Factory.create(:merge_request, :title => arg2, :project => project, :author => project.users.first)
-end
-
-Given /^project "(.*?)" have "(.*?)" closed merge request$/ do |arg1, arg2|
- project = Project.find_by_name(arg1)
- Factory.create(:merge_request, :title => arg2, :project => project, :author => project.users.first, :closed => true)
-end
-
-Given /^I visit project "(.*?)" merge requests page$/ do |arg1|
- visit project_merge_requests_path(Project.find_by_name(arg1))
-end
-
-Then /^I should see "(.*?)" in merge requests$/ do |arg1|
- page.should have_content arg1
-end
-
-Then /^I should not see "(.*?)" in merge requests$/ do |arg1|
- page.should_not have_content arg1
-end
-
-Then /^I should see merge request "(.*?)"$/ do |arg1|
- merge_request = MergeRequest.find_by_title(arg1)
- page.should have_content(merge_request.title[0..10])
- page.should have_content(merge_request.target_branch)
- page.should have_content(merge_request.source_branch)
-end
-
-Given /^I submit new merge request "(.*?)"$/ do |arg1|
- fill_in "merge_request_title", :with => arg1
- select "master", :from => "merge_request_source_branch"
- select "stable", :from => "merge_request_target_branch"
- click_button "Save"
-end
-
-Given /^I visit merge request page "(.*?)"$/ do |arg1|
- mr = MergeRequest.find_by_title(arg1)
- visit project_merge_request_path(mr.project, mr)
-end
-
-Then /^I should see closed merge request "(.*?)"$/ do |arg1|
- mr = MergeRequest.find_by_title(arg1)
- mr.closed.should be_true
- page.should have_content "Closed by"
-end
-
diff --git a/features/step_definitions/project/project_milestones_steps.rb b/features/step_definitions/project/project_milestones_steps.rb
deleted file mode 100644
index 6749773e..00000000
--- a/features/step_definitions/project/project_milestones_steps.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-Given /^project "(.*?)" has milestone "(.*?)"$/ do |arg1, arg2|
- project = Project.find_by_name(arg1)
-
- milestone = Factory :milestone,
- :title => arg2,
- :project => project
-
- 3.times do |i|
- issue = Factory :issue,
- :project => project,
- :milestone => milestone
- end
-end
-
-Given /^I visit project "(.*?)" milestones page$/ do |arg1|
- @project = Project.find_by_name(arg1)
- visit project_milestones_path(@project)
-end
-
-Then /^I should see active milestones$/ do
- milestone = @project.milestones.first
- page.should have_content(milestone.title[0..10])
- page.should have_content(milestone.expires_at)
- page.should have_content("Browse Issues")
-end
-
-Then /^I should see milestone "(.*?)"$/ do |arg1|
- milestone = @project.milestones.find_by_title(arg1)
- page.should have_content(milestone.title[0..10])
- page.should have_content(milestone.expires_at)
- page.should have_content("Browse Issues")
-end
-
-Given /^I submit new milestone "(.*?)"$/ do |arg1|
- fill_in "milestone_title", :with => arg1
- click_button "Create milestone"
-end
-
diff --git a/features/step_definitions/project/project_team_steps.rb b/features/step_definitions/project/project_team_steps.rb
deleted file mode 100644
index f0bab29a..00000000
--- a/features/step_definitions/project/project_team_steps.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-Given /^gitlab user "(.*?)"$/ do |arg1|
- Factory :user, :name => arg1
-end
-
-Given /^"(.*?)" is "(.*?)" developer$/ do |arg1, arg2|
- user = User.find_by_name(arg1)
- project = Project.find_by_name(arg2)
- project.add_access(user, :write)
-end
-
-Given /^I visit project "(.*?)" team page$/ do |arg1|
- visit team_project_path(Project.find_by_name(arg1))
-end
-
-Then /^I should be able to see myself in team$/ do
- page.should have_content(@user.name)
- page.should have_content(@user.email)
-end
-
-Then /^I should see "(.*?)" in team list$/ do |arg1|
- user = User.find_by_name(arg1)
- page.should have_content(user.name)
- page.should have_content(user.email)
-end
-
-Given /^I click link "(.*?)"$/ do |arg1|
- click_link arg1
-end
-
-Given /^I select "(.*?)" as "(.*?)"$/ do |arg1, arg2|
- user = User.find_by_name(arg1)
- within "#new_team_member" do
- select user.name, :from => "team_member_user_id"
- select arg2, :from => "team_member_project_access"
- end
- click_button "Save"
-end
-
-Then /^I should see "(.*?)" in team list as "(.*?)"$/ do |arg1, arg2|
- user = User.find_by_name(arg1)
- role_id = find(".user_#{user.id} #team_member_project_access").value
- role_id.should == UsersProject.access_roles[arg2].to_s
-end
-
-Given /^I change "(.*?)" role to "(.*?)"$/ do |arg1, arg2|
- user = User.find_by_name(arg1)
- within ".user_#{user.id}" do
- select arg2, :from => "team_member_project_access"
- end
-end
-
-Then /^I should see "(.*?)" team profile$/ do |arg1|
- user = User.find_by_name(arg1)
- page.should have_content(user.name)
- page.should have_content(user.email)
- page.should have_content("To team list")
-end
-
-Then /^I should not see "(.*?)" in team list$/ do |arg1|
- user = User.find_by_name(arg1)
- page.should_not have_content(user.name)
- page.should_not have_content(user.email)
-end
diff --git a/features/step_definitions/project/project_wiki_steps.rb b/features/step_definitions/project/project_wiki_steps.rb
deleted file mode 100644
index 10de38d9..00000000
--- a/features/step_definitions/project/project_wiki_steps.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-Given /^I visit project wiki page$/ do
- visit project_wiki_path(@project, :index)
-end
-
-Given /^I create Wiki page$/ do
- fill_in "Title", :with => 'Test title'
- fill_in "Content", :with => '[link test](test)'
- click_on "Save"
-end
-
-Then /^I should see newly created wiki page$/ do
- page.should have_content("Test title")
- page.should have_content("link test")
-
- click_link "link test"
-
- page.should have_content("Editing page")
-end
diff --git a/features/step_definitions/project/projects_steps.rb b/features/step_definitions/project/projects_steps.rb
deleted file mode 100644
index 3ff08d58..00000000
--- a/features/step_definitions/project/projects_steps.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-include LoginMacros
-
-Given /^I signin as a user$/ do
- login_as :user
-end
-
-When /^I visit new project page$/ do
- visit new_project_path
-end
-
-When /^fill project form with valid data$/ do
- fill_in 'project_name', :with => 'NewProject'
- fill_in 'project_code', :with => 'NPR'
- fill_in 'project_path', :with => 'newproject'
- click_button "Create project"
-end
-
-Then /^I should see project page$/ do
- current_path.should == project_path(Project.last)
- page.should have_content('NewProject')
-end
-
-Then /^I should see empty project instuctions$/ do
- page.should have_content("git init")
- page.should have_content("git remote")
- page.should have_content(Project.last.url_to_repo)
-end
-
-Given /^I own project "(.*?)"$/ do |arg1|
- @project = Factory :project, :name => arg1
- @project.add_access(@user, :admin)
-end
-
-Given /^I visit project "(.*?)" wall page$/ do |arg1|
- project = Project.find_by_name(arg1)
- visit wall_project_path(project)
-end
-
-Then /^I should see project wall note "(.*?)"$/ do |arg1|
- page.should have_content arg1
-end
-
-Given /^project "(.*?)" has comment "(.*?)"$/ do |arg1, arg2|
- project = Project.find_by_name(arg1)
- project.notes.create(:note => arg1, :author => project.users.first)
-end
-
-Given /^I write new comment "(.*?)"$/ do |arg1|
- fill_in "note_note", :with => arg1
- click_button "Add Comment"
-end
-
-Given /^I visit project "(.*?)" page$/ do |arg1|
- project = Project.find_by_name(arg1)
- visit project_path(project)
-end
-
-Given /^I visit project "(.*?)" network page$/ do |arg1|
- project = Project.find_by_name(arg1)
-
- # Stub out find_all to speed this up (10 commits vs. 650)
- commits = Grit::Commit.find_all(project.repo, nil, {max_count: 10})
- Grit::Commit.stub(:find_all).and_return(commits)
-
- visit graph_project_path(project)
-end
-
-Given /^show me page$/ do
- save_and_open_page
-end
-
-Given /^page should have network graph$/ do
- page.should have_content "Project Network Graph"
- within ".graph" do
- page.should have_content "master"
- page.should have_content "scss_refactor..."
- end
-end
-
-Given /^I leave a comment like "(.*?)"$/ do |arg1|
- fill_in "note_note", :with => arg1
- click_button "Add Comment"
-end
-
-Then /^I should see comment "(.*?)"$/ do |arg1|
- page.should have_content(arg1)
-end
diff --git a/features/steps/dashboard/dashboard.rb b/features/steps/dashboard/dashboard.rb
new file mode 100644
index 00000000..6c603bbe
--- /dev/null
+++ b/features/steps/dashboard/dashboard.rb
@@ -0,0 +1,92 @@
+class Dashboard < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedPaths
+
+ Then 'I should see "New Project" link' do
+ page.should have_link "New Project"
+ end
+
+ Then 'I should see "Shop" project link' do
+ page.should have_link "Shop"
+ end
+
+ Then 'I should see project "Shop" activity feed' do
+ project = Project.find_by_name("Shop")
+ page.should have_content "#{@user.name} pushed new branch new_design at #{project.name}"
+ end
+
+ Then 'I should see last push widget' do
+ page.should have_content "Your pushed to branch new_design"
+ page.should have_link "Create Merge Request"
+ end
+
+ And 'I click "Create Merge Request" link' do
+ click_link "Create Merge Request"
+ end
+
+ Then 'I see prefilled new Merge Request page' do
+ current_path.should == new_project_merge_request_path(@project)
+ find("#merge_request_source_branch").value.should == "new_design"
+ find("#merge_request_target_branch").value.should == "master"
+ find("#merge_request_title").value.should == "New Design"
+ end
+
+ Given 'user with name "John Doe" joined project "Shop"' do
+ user = Factory.create(:user, {name: "John Doe"})
+ project = Project.find_by_name "Shop"
+ Event.create(
+ project: project,
+ author_id: user.id,
+ action: Event::Joined
+ )
+ end
+
+ Then 'I should see "John Doe joined project Shop" event' do
+ page.should have_content "John Doe joined project Shop"
+ end
+
+ And 'user with name "John Doe" left project "Shop"' do
+ user = User.find_by_name "John Doe"
+ project = Project.find_by_name "Shop"
+ Event.create(
+ project: project,
+ author_id: user.id,
+ action: Event::Left
+ )
+ end
+
+ Then 'I should see "John Doe left project Shop" event' do
+ page.should have_content "John Doe left project Shop"
+ end
+
+ And 'I own project "Shop"' do
+ @project = Factory :project, :name => 'Shop'
+ @project.add_access(@user, :admin)
+ end
+
+ And 'project "Shop" has push event' do
+ @project = Project.find_by_name("Shop")
+
+ data = {
+ :before => "0000000000000000000000000000000000000000",
+ :after => "0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e",
+ :ref => "refs/heads/new_design",
+ :user_id => @user.id,
+ :user_name => @user.name,
+ :repository => {
+ :name => @project.name,
+ :url => "localhost/rubinius",
+ :description => "",
+ :homepage => "localhost/rubinius",
+ :private => true
+ }
+ }
+
+ @event = Event.create(
+ :project => @project,
+ :action => Event::Pushed,
+ :data => data,
+ :author_id => @user.id
+ )
+ end
+end
diff --git a/features/steps/dashboard/dashboard_issues.rb b/features/steps/dashboard/dashboard_issues.rb
new file mode 100644
index 00000000..9368782b
--- /dev/null
+++ b/features/steps/dashboard/dashboard_issues.rb
@@ -0,0 +1,19 @@
+class DashboardIssues < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedPaths
+
+ Then 'I should see issues assigned to me' do
+ issues = @user.issues
+ issues.each do |issue|
+ page.should have_content(issue.title[0..10])
+ page.should have_content(issue.project.name)
+ end
+ end
+
+ And 'I have assigned issues' do
+ project = Factory :project
+ project.add_access(@user, :read, :write)
+
+ 2.times { Factory :issue, :author => @user, :assignee => @user, :project => project }
+ end
+end
diff --git a/features/steps/dashboard/dashboard_merge_requests.rb b/features/steps/dashboard/dashboard_merge_requests.rb
new file mode 100644
index 00000000..fc339e75
--- /dev/null
+++ b/features/steps/dashboard/dashboard_merge_requests.rb
@@ -0,0 +1,23 @@
+class DashboardMergeRequests < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedPaths
+
+ Then 'I should see my merge requests' do
+ merge_requests = @user.merge_requests
+ merge_requests.each do |mr|
+ page.should have_content(mr.title[0..10])
+ page.should have_content(mr.project.name)
+ end
+ end
+
+ And 'I have authored merge requests' do
+ project1 = Factory :project
+ project2 = Factory :project
+
+ project1.add_access(@user, :read, :write)
+ project2.add_access(@user, :read, :write)
+
+ merge_request1 = Factory :merge_request, :author => @user, :project => project1
+ merge_request2 = Factory :merge_request, :author => @user, :project => project2
+ end
+end
diff --git a/features/steps/dashboard/dashboard_search.rb b/features/steps/dashboard/dashboard_search.rb
new file mode 100644
index 00000000..e3585898
--- /dev/null
+++ b/features/steps/dashboard/dashboard_search.rb
@@ -0,0 +1,18 @@
+class DashboardSearch < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedPaths
+
+ Given 'I search for "Sho"' do
+ fill_in "dashboard_search", :with => "Sho"
+ click_button "Search"
+ end
+
+ Then 'I should see "Shop" project link' do
+ page.should have_link "Shop"
+ end
+
+ And 'I own project "Shop"' do
+ @project = Factory :project, :name => "Shop"
+ @project.add_access(@user, :admin)
+ end
+end
diff --git a/features/steps/profile/profile.rb b/features/steps/profile/profile.rb
new file mode 100644
index 00000000..d3261a16
--- /dev/null
+++ b/features/steps/profile/profile.rb
@@ -0,0 +1,44 @@
+class Profile < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedPaths
+
+ Then 'I should see my profile info' do
+ page.should have_content "Profile"
+ page.should have_content @user.name
+ page.should have_content @user.email
+ end
+
+ Then 'I change my contact info' do
+ fill_in "user_skype", :with => "testskype"
+ fill_in "user_linkedin", :with => "testlinkedin"
+ fill_in "user_twitter", :with => "testtwitter"
+ click_button "Save"
+ @user.reload
+ end
+
+ And 'I should see new contact info' do
+ @user.skype.should == 'testskype'
+ @user.linkedin.should == 'testlinkedin'
+ @user.twitter.should == 'testtwitter'
+ end
+
+ Then 'I change my password' do
+ fill_in "user_password", :with => "222333"
+ fill_in "user_password_confirmation", :with => "222333"
+ click_button "Save"
+ end
+
+ And 'I should be redirected to sign in page' do
+ current_path.should == new_user_session_path
+ end
+
+ Then 'I reset my token' do
+ @old_token = @user.private_token
+ click_button "Reset"
+ end
+
+ And 'I should see new token' do
+ find("#token").value.should_not == @old_token
+ find("#token").value.should == @user.reload.private_token
+ end
+end
diff --git a/features/steps/profile/profile_ssh_keys.rb b/features/steps/profile/profile_ssh_keys.rb
new file mode 100644
index 00000000..96df2d73
--- /dev/null
+++ b/features/steps/profile/profile_ssh_keys.rb
@@ -0,0 +1,48 @@
+class ProfileSshKeys < Spinach::FeatureSteps
+ include SharedAuthentication
+
+ Then 'I should see my ssh keys' do
+ @user.keys.each do |key|
+ page.should have_content(key.title)
+ end
+ end
+
+ Given 'I click link "Add new"' do
+ click_link "Add new"
+ end
+
+ And 'I submit new ssh key "Laptop"' do
+ fill_in "key_title", :with => "Laptop"
+ fill_in "key_key", :with => "ssh-rsa publickey234="
+ click_button "Save"
+ end
+
+ Then 'I should see new ssh key "Laptop"' do
+ key = Key.find_by_title("Laptop")
+ page.should have_content(key.title)
+ page.should have_content(key.key)
+ current_path.should == key_path(key)
+ end
+
+ Given 'I click link "Work"' do
+ click_link "Work"
+ end
+
+ And 'I click link "Remove"' do
+ click_link "Remove"
+ end
+
+ Then 'I visit profile keys page' do
+ visit keys_path
+ end
+
+ And 'I should not see "Work" ssh key' do
+ within "#keys-table" do
+ page.should_not have_content "Work"
+ end
+ end
+
+ And 'I have ssh key "ssh-rsa Work"' do
+ Factory :key, :user => @user, :title => "ssh-rsa Work", :key => "jfKLJDFKSFJSHFJssh-rsa Work"
+ end
+end
diff --git a/features/steps/project/create_project.rb b/features/steps/project/create_project.rb
new file mode 100644
index 00000000..6d2ca3f9
--- /dev/null
+++ b/features/steps/project/create_project.rb
@@ -0,0 +1,22 @@
+class CreateProject < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedPaths
+
+ And 'fill project form with valid data' do
+ fill_in 'project_name', :with => 'NewProject'
+ fill_in 'project_code', :with => 'NPR'
+ fill_in 'project_path', :with => 'newproject'
+ click_button "Create project"
+ end
+
+ Then 'I should see project page' do
+ current_path.should == project_path(Project.last)
+ page.should have_content "NewProject"
+ end
+
+ And 'I should see empty project instuctions' do
+ page.should have_content "git init"
+ page.should have_content "git remote"
+ page.should have_content Project.last.url_to_repo
+ end
+end
diff --git a/features/steps/project/project.rb b/features/steps/project/project.rb
new file mode 100644
index 00000000..f33f12eb
--- /dev/null
+++ b/features/steps/project/project.rb
@@ -0,0 +1,5 @@
+class Projects < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedPaths
+end
diff --git a/features/steps/project/project_browse_branches.rb b/features/steps/project/project_browse_branches.rb
new file mode 100644
index 00000000..2f6e185d
--- /dev/null
+++ b/features/steps/project/project_browse_branches.rb
@@ -0,0 +1,35 @@
+class ProjectBrowseBranches < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedPaths
+
+ Then 'I should see "Shop" recent branches list' do
+ page.should have_content "Branches"
+ page.should have_content "master"
+ end
+
+ Given 'I click link "All"' do
+ click_link "All"
+ end
+
+ Then 'I should see "Shop" all branches list' do
+ page.should have_content "Branches"
+ page.should have_content "master"
+ end
+
+ Given 'I click link "Protected"' do
+ click_link "Protected"
+ end
+
+ Then 'I should see "Shop" protected branches list' do
+ within "table" do
+ page.should have_content "stable"
+ page.should_not have_content "master"
+ end
+ end
+
+ And 'project "Shop" has protected branches' do
+ project = Project.find_by_name("Shop")
+ project.protected_branches.create(:name => "stable")
+ end
+end
diff --git a/features/steps/project/project_browse_commits.rb b/features/steps/project/project_browse_commits.rb
new file mode 100644
index 00000000..01479987
--- /dev/null
+++ b/features/steps/project/project_browse_commits.rb
@@ -0,0 +1,47 @@
+class ProjectBrowseCommits < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedPaths
+
+ Then 'I see project commits' do
+ current_path.should == project_commits_path(@project)
+
+ commit = @project.commit
+ page.should have_content(@project.name)
+ page.should have_content(commit.message)
+ page.should have_content(commit.id.to_s[0..5])
+ end
+
+ Given 'I click atom feed link' do
+ click_link "Feed"
+ end
+
+ Then 'I see commits atom feed' do
+ commit = CommitDecorator.decorate(@project.commit)
+ page.response_headers['Content-Type'].should have_content("application/atom+xml")
+ page.body.should have_selector("title", :text => "Recent commits to #{@project.name}")
+ page.body.should have_selector("author email", :text => commit.author_email)
+ page.body.should have_selector("entry summary", :text => commit.description)
+ end
+
+ Given 'I click on commit link' do
+ visit project_commit_path(@project, ValidCommit::ID)
+ end
+
+ Then 'I see commit info' do
+ page.should have_content ValidCommit::MESSAGE
+ page.should have_content "Showing 1 changed file"
+ end
+
+ And 'I fill compare fields with refs' do
+ fill_in "from", :with => "master"
+ fill_in "to", :with => "stable"
+ click_button "Compare"
+ end
+
+ And 'I see compared refs' do
+ page.should have_content "Commits (27)"
+ page.should have_content "Compare View"
+ page.should have_content "Showing 73 changed files"
+ end
+end
diff --git a/features/steps/project/project_browse_files.rb b/features/steps/project/project_browse_files.rb
new file mode 100644
index 00000000..67c553ce
--- /dev/null
+++ b/features/steps/project/project_browse_files.rb
@@ -0,0 +1,34 @@
+class ProjectBrowseFiles < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedPaths
+
+ Then 'I should see files from repository' do
+ page.should have_content "app"
+ page.should have_content "History"
+ page.should have_content "Gemfile"
+ end
+
+ Then 'I should see files from repository for "8470d70"' do
+ current_path.should == tree_project_ref_path(@project, "8470d70")
+ page.should have_content "app"
+ page.should have_content "History"
+ page.should have_content "Gemfile"
+ end
+
+ Given 'I click on "Gemfile" file in repo' do
+ click_link "Gemfile"
+ end
+
+ Then 'I should see it content' do
+ page.should have_content "rubygems.org"
+ end
+
+ And 'I click link "raw"' do
+ click_link "raw"
+ end
+
+ Then 'I should see raw file content' do
+ page.source.should == ValidCommit::BLOB_FILE
+ end
+end
diff --git a/features/steps/project/project_browse_git_repo.rb b/features/steps/project/project_browse_git_repo.rb
new file mode 100644
index 00000000..e966f407
--- /dev/null
+++ b/features/steps/project/project_browse_git_repo.rb
@@ -0,0 +1,19 @@
+class ProjectBrowseGitRepo < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedPaths
+
+ Given 'I click on "Gemfile" file in repo' do
+ click_link "Gemfile"
+ end
+
+ And 'I click blame button' do
+ click_link "blame"
+ end
+
+ Then 'I should see git file blame' do
+ page.should have_content "rubygems.org"
+ page.should have_content "Dmitriy Zaporozhets"
+ page.should have_content "bc3735004cb Moving to rails 3.2"
+ end
+end
diff --git a/features/steps/project/project_browse_tags.rb b/features/steps/project/project_browse_tags.rb
new file mode 100644
index 00000000..0cbfa0d8
--- /dev/null
+++ b/features/steps/project/project_browse_tags.rb
@@ -0,0 +1,10 @@
+class ProjectBrowseTags < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedPaths
+
+ Then 'I should see "Shop" all tags list' do
+ page.should have_content "Tags"
+ page.should have_content "v1.2.1"
+ end
+end
diff --git a/features/steps/project/project_comment_commit.rb b/features/steps/project/project_comment_commit.rb
new file mode 100644
index 00000000..cb8385e1
--- /dev/null
+++ b/features/steps/project/project_comment_commit.rb
@@ -0,0 +1,6 @@
+class ProjectCommentCommit < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedNote
+ include SharedPaths
+end
diff --git a/features/steps/project/project_issues.rb b/features/steps/project/project_issues.rb
new file mode 100644
index 00000000..64af2449
--- /dev/null
+++ b/features/steps/project/project_issues.rb
@@ -0,0 +1,134 @@
+class ProjectIssues < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedNote
+ include SharedPaths
+
+ Given 'I should see "Release 0.4" in issues' do
+ page.should have_content "Release 0.4"
+ end
+
+ And 'I should not see "Release 0.3" in issues' do
+ page.should_not have_content "Release 0.3"
+ end
+
+ Given 'I click link "Closed"' do
+ click_link "Closed"
+ end
+
+ Then 'I should see "Release 0.3" in issues' do
+ page.should have_content "Release 0.3"
+ end
+
+ And 'I should not see "Release 0.4" in issues' do
+ page.should_not have_content "Release 0.4"
+ end
+
+ Given 'I click link "All"' do
+ click_link "All"
+ end
+
+ Given 'I click link "Release 0.4"' do
+ click_link "Release 0.4"
+ end
+
+ Then 'I should see issue "Release 0.4"' do
+ page.should have_content "Release 0.4"
+ end
+
+ Given 'I click link "New Issue"' do
+ click_link "New Issue"
+ end
+
+ And 'I submit new issue "500 error on profile"' do
+ fill_in "issue_title", :with => "500 error on profile"
+ click_button "Submit new issue"
+ end
+
+ Given 'I click link "500 error on profile"' do
+ click_link "500 error on profile"
+ end
+
+ Then 'I should see issue "500 error on profile"' do
+ issue = Issue.find_by_title("500 error on profile")
+ page.should have_content issue.title
+ page.should have_content issue.author_name
+ page.should have_content issue.project.name
+ end
+
+ Given 'I fill in issue search with "Release"' do
+ fill_in 'issue_search', with: "Release"
+ end
+
+ Given 'I fill in issue search with "Bug"' do
+ fill_in 'issue_search', with: "Bug"
+ end
+
+ And 'I fill in issue search with "0.3"' do
+ fill_in 'issue_search', with: "0.3"
+ end
+
+ And 'I fill in issue search with "Something"' do
+ fill_in 'issue_search', with: "Something"
+ end
+
+ And 'I fill in issue search with ""' do
+ page.execute_script("$('.issue_search').val('').keyup();");
+ fill_in 'issue_search', with: ""
+ end
+
+ Given 'project "Shop" has milestone "v2.2"' do
+ project = Project.find_by_name("Shop")
+ milestone = Factory :milestone, :title => "v2.2", :project => project
+
+ 3.times { Factory :issue, :project => project, :milestone => milestone }
+ end
+
+ And 'project "Shop" has milestone "v3.0"' do
+ project = Project.find_by_name("Shop")
+ milestone = Factory :milestone, :title => "v3.0", :project => project
+
+ 3.times { Factory :issue, :project => project, :milestone => milestone }
+ end
+
+ When 'I select milestone "v3.0"' do
+ select "v3.0", from: "milestone_id"
+ end
+
+ Then 'I should see selected milestone with title "v3.0"' do
+ issues_milestone_selector = "#issue_milestone_id_chzn/a"
+ wait_until { page.has_content?("Details") }
+ page.find(issues_milestone_selector).should have_content("v3.0")
+ end
+
+ When 'I select first assignee from "Shop" project' do
+ project = Project.find_by_name "Shop"
+ first_assignee = project.users.first
+ select first_assignee.name, from: "assignee_id"
+ end
+
+ Then 'I should see first assignee from "Shop" as selected assignee' do
+ issues_assignee_selector = "#issue_assignee_id_chzn/a"
+ wait_until { page.has_content?("Details") }
+ project = Project.find_by_name "Shop"
+ assignee_name = project.users.first.name
+ page.find(issues_assignee_selector).should have_content(assignee_name)
+ end
+
+ And 'project "Shop" have "Release 0.4" open issue' do
+ project = Project.find_by_name("Shop")
+ Factory.create(:issue,
+ :title => "Release 0.4",
+ :project => project,
+ :author => project.users.first)
+ end
+
+ And 'project "Shop" have "Release 0.3" closed issue' do
+ project = Project.find_by_name("Shop")
+ Factory.create(:issue,
+ :title => "Release 0.3",
+ :project => project,
+ :author => project.users.first,
+ :closed => true)
+ end
+end
diff --git a/features/steps/project/project_labels.rb b/features/steps/project/project_labels.rb
new file mode 100644
index 00000000..1a347bf3
--- /dev/null
+++ b/features/steps/project/project_labels.rb
@@ -0,0 +1,24 @@
+class ProjectLabels < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedPaths
+
+ Then 'I should see label "bug"' do
+ within ".labels-table" do
+ page.should have_content "bug"
+ end
+ end
+
+ And 'I should see label "feature"' do
+ within ".labels-table" do
+ page.should have_content "feature"
+ end
+ end
+
+ And 'project "Shop" have issues tags: "bug", "feature"' do
+ project = Project.find_by_name("Shop")
+ ['bug', 'feature'].each do |label|
+ Factory :issue, project: project, label_list: label
+ end
+ end
+end
diff --git a/features/steps/project/project_merge_requests.rb b/features/steps/project/project_merge_requests.rb
new file mode 100644
index 00000000..80e83906
--- /dev/null
+++ b/features/steps/project/project_merge_requests.rb
@@ -0,0 +1,80 @@
+class ProjectMergeRequests < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedNote
+ include SharedPaths
+
+ Then 'I should see "Bug NS-04" in merge requests' do
+ page.should have_content "Bug NS-04"
+ end
+
+ And 'I should not see "Feature NS-03" in merge requests' do
+ page.should_not have_content "Feature NS-03"
+ end
+
+ Given 'I click link "Closed"' do
+ click_link "Closed"
+ end
+
+ Then 'I should see "Feature NS-03" in merge requests' do
+ page.should have_content "Feature NS-03"
+ end
+
+ And 'I should not see "Bug NS-04" in merge requests' do
+ page.should_not have_content "Bug NS-04"
+ end
+
+ Given 'I click link "All"' do
+ click_link "All"
+ end
+
+ Given 'I click link "Bug NS-04"' do
+ click_link "Bug NS-04"
+ end
+
+ Then 'I should see merge request "Bug NS-04"' do
+ page.should have_content "Bug NS-04"
+ end
+
+ And 'I click link "Close"' do
+ click_link "Close"
+ end
+
+ Then 'I should see closed merge request "Bug NS-04"' do
+ mr = MergeRequest.find_by_title("Bug NS-04")
+ mr.closed.should be_true
+ page.should have_content "Closed by"
+ end
+
+ Given 'I click link "New Merge Request"' do
+ click_link "New Merge Request"
+ end
+
+ And 'I submit new merge request "Wiki Feature"' do
+ fill_in "merge_request_title", :with => "Wiki Feature"
+ select "master", :from => "merge_request_source_branch"
+ select "stable", :from => "merge_request_target_branch"
+ click_button "Save"
+ end
+
+ Then 'I should see merge request "Wiki Feature"' do
+ page.should have_content "Wiki Feature"
+ end
+
+ And 'project "Shop" have "Bug NS-04" open merge request' do
+ project = Project.find_by_name("Shop")
+ Factory.create(:merge_request,
+ :title => "Bug NS-04",
+ :project => project,
+ :author => project.users.first)
+ end
+
+ And 'project "Shop" have "Feature NS-03" closed merge request' do
+ project = Project.find_by_name("Shop")
+ Factory.create(:merge_request,
+ :title => "Feature NS-03",
+ :project => project,
+ :author => project.users.first,
+ :closed => true)
+ end
+end
diff --git a/features/steps/project/project_milestones.rb b/features/steps/project/project_milestones.rb
new file mode 100644
index 00000000..83ed6859
--- /dev/null
+++ b/features/steps/project/project_milestones.rb
@@ -0,0 +1,39 @@
+class ProjectMilestones < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedPaths
+
+ Then 'I should see milestone "v2.2"' do
+ milestone = @project.milestones.find_by_title("v2.2")
+ page.should have_content(milestone.title[0..10])
+ page.should have_content(milestone.expires_at)
+ page.should have_content("Browse Issues")
+ end
+
+ Given 'I click link "v2.2"' do
+ click_link "v2.2"
+ end
+
+ Given 'I click link "New Milestone"' do
+ click_link "New Milestone"
+ end
+
+ And 'I submit new milestone "v2.3"' do
+ fill_in "milestone_title", :with => "v2.3"
+ click_button "Create milestone"
+ end
+
+ Then 'I should see milestone "v2.3"' do
+ milestone = @project.milestones.find_by_title("v2.3")
+ page.should have_content(milestone.title[0..10])
+ page.should have_content(milestone.expires_at)
+ page.should have_content("Browse Issues")
+ end
+
+ And 'project "Shop" has milestone "v2.2"' do
+ project = Project.find_by_name("Shop")
+ milestone = Factory :milestone, :title => "v2.2", :project => project
+
+ 3.times { Factory :issue, :project => project, :milestone => milestone }
+ end
+end
diff --git a/features/steps/project/project_network_graph.rb b/features/steps/project/project_network_graph.rb
new file mode 100644
index 00000000..f34a81a4
--- /dev/null
+++ b/features/steps/project/project_network_graph.rb
@@ -0,0 +1,22 @@
+class ProjectNetworkGraph < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+
+ Then 'page should have network graph' do
+ page.should have_content "Project Network Graph"
+ within ".graph" do
+ page.should have_content "master"
+ page.should have_content "scss_refactor..."
+ end
+ end
+
+ And 'I visit project "Shop" network page' do
+ project = Project.find_by_name("Shop")
+
+ # Stub out find_all to speed this up (10 commits vs. 650)
+ commits = Grit::Commit.find_all(project.repo, nil, {max_count: 10})
+ Grit::Commit.stub(:find_all).and_return(commits)
+
+ visit graph_project_path(project)
+ end
+end
diff --git a/features/steps/project/project_team_management.rb b/features/steps/project/project_team_management.rb
new file mode 100644
index 00000000..7beca257
--- /dev/null
+++ b/features/steps/project/project_team_management.rb
@@ -0,0 +1,89 @@
+class ProjectTeamManagement < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedPaths
+
+ Then 'I should be able to see myself in team' do
+ page.should have_content(@user.name)
+ page.should have_content(@user.email)
+ end
+
+ And 'I should see "Sam" in team list' do
+ user = User.find_by_name("Sam")
+ page.should have_content(user.name)
+ page.should have_content(user.email)
+ end
+
+ Given 'I click link "New Team Member"' do
+ click_link "New Team Member"
+ end
+
+ And 'I select "Mike" as "Reporter"' do
+ user = User.find_by_name("Mike")
+ within "#new_team_member" do
+ select user.name, :from => "user_ids"
+ select "Reporter", :from => "project_access"
+ end
+ click_button "Save"
+ end
+
+ Then 'I should see "Mike" in team list as "Reporter"' do
+ user = User.find_by_name("Mike")
+ role_id = find(".user_#{user.id} #team_member_project_access").value
+ role_id.should == UsersProject.access_roles["Reporter"].to_s
+ end
+
+ Given 'I should see "Sam" in team list as "Developer"' do
+ user = User.find_by_name("Sam")
+ role_id = find(".user_#{user.id} #team_member_project_access").value
+ role_id.should == UsersProject.access_roles["Developer"].to_s
+ end
+
+ And 'I change "Sam" role to "Reporter"' do
+ user = User.find_by_name("Sam")
+ within ".user_#{user.id}" do
+ select "Reporter", :from => "team_member_project_access"
+ end
+ end
+
+ And 'I should see "Sam" in team list as "Reporter"' do
+ user = User.find_by_name("Sam")
+ role_id = find(".user_#{user.id} #team_member_project_access").value
+ role_id.should == UsersProject.access_roles["Reporter"].to_s
+ end
+
+ Given 'I click link "Sam"' do
+ click_link "Sam"
+ end
+
+ Then 'I should see "Sam" team profile' do
+ user = User.find_by_name("Sam")
+ page.should have_content(user.name)
+ page.should have_content(user.email)
+ page.should have_content("To team list")
+ end
+
+ And 'I click link "Remove from team"' do
+ click_link "Remove from team"
+ end
+
+ And 'I should not see "Sam" in team list' do
+ user = User.find_by_name("Sam")
+ page.should_not have_content(user.name)
+ page.should_not have_content(user.email)
+ end
+
+ And 'gitlab user "Mike"' do
+ Factory :user, :name => "Mike"
+ end
+
+ And 'gitlab user "Sam"' do
+ Factory :user, :name => "Sam"
+ end
+
+ And '"Sam" is "Shop" developer' do
+ user = User.find_by_name("Sam")
+ project = Project.find_by_name("Shop")
+ project.add_access(user, :write)
+ end
+end
diff --git a/features/steps/project/project_wall.rb b/features/steps/project/project_wall.rb
new file mode 100644
index 00000000..ba9d3533
--- /dev/null
+++ b/features/steps/project/project_wall.rb
@@ -0,0 +1,6 @@
+class ProjectWall < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedNote
+ include SharedPaths
+end
diff --git a/features/steps/project/project_wiki.rb b/features/steps/project/project_wiki.rb
new file mode 100644
index 00000000..902e9ce1
--- /dev/null
+++ b/features/steps/project/project_wiki.rb
@@ -0,0 +1,20 @@
+class ProjectWiki < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedNote
+ include SharedPaths
+
+ Given 'I create Wiki page' do
+ fill_in "Title", :with => 'Test title'
+ fill_in "Content", :with => '[link test](test)'
+ click_on "Save"
+ end
+
+ Then 'I should see newly created wiki page' do
+ page.should have_content "Test title"
+ page.should have_content "link test"
+
+ click_link "link test"
+ page.should have_content "Editing page"
+ end
+end
diff --git a/features/steps/shared/authentication.rb b/features/steps/shared/authentication.rb
new file mode 100644
index 00000000..77d9839f
--- /dev/null
+++ b/features/steps/shared/authentication.rb
@@ -0,0 +1,10 @@
+require Rails.root.join('spec', 'support', 'login_helpers')
+
+module SharedAuthentication
+ include Spinach::DSL
+ include LoginHelpers
+
+ Given 'I sign in as a user' do
+ login_as :user
+ end
+end
diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb
new file mode 100644
index 00000000..923e69b6
--- /dev/null
+++ b/features/steps/shared/note.rb
@@ -0,0 +1,21 @@
+module SharedNote
+ include Spinach::DSL
+
+ Given 'I leave a comment like "XML attached"' do
+ fill_in "note_note", :with => "XML attached"
+ click_button "Add Comment"
+ end
+
+ Then 'I should see comment "XML attached"' do
+ page.should have_content "XML attached"
+ end
+
+ Given 'I write new comment "my special test message"' do
+ fill_in "note_note", :with => "my special test message"
+ click_button "Add Comment"
+ end
+
+ Then 'I should see project wall note "my special test message"' do
+ page.should have_content "my special test message"
+ end
+end
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
new file mode 100644
index 00000000..93ad0219
--- /dev/null
+++ b/features/steps/shared/paths.rb
@@ -0,0 +1,112 @@
+module SharedPaths
+ include Spinach::DSL
+
+ And 'I visit dashboard search page' do
+ visit search_path
+ end
+
+ And 'I visit dashboard merge requests page' do
+ visit dashboard_merge_requests_path
+ end
+
+ And 'I visit dashboard issues page' do
+ visit dashboard_issues_path
+ end
+
+ When 'I visit dashboard page' do
+ visit dashboard_path
+ end
+
+ Given 'I visit profile page' do
+ visit profile_path
+ end
+
+ Given 'I visit profile account page' do
+ visit profile_account_path
+ end
+
+ Given 'I visit profile token page' do
+ visit profile_token_path
+ end
+
+ When 'I visit new project page' do
+ visit new_project_path
+ end
+
+ And 'I visit project "Shop" page' do
+ project = Project.find_by_name("Shop")
+ visit project_path(project)
+ end
+
+ Given 'I visit project branches page' do
+ visit branches_project_repository_path(@project)
+ end
+
+ Given 'I visit compare refs page' do
+ visit compare_project_commits_path(@project)
+ end
+
+ Given 'I visit project commits page' do
+ visit project_commits_path(@project)
+ end
+
+ Given 'I visit project source page' do
+ visit tree_project_ref_path(@project, @project.root_ref)
+ end
+
+ Given 'I visit blob file from repo' do
+ visit tree_project_ref_path(@project, ValidCommit::ID, :path => ValidCommit::BLOB_FILE_PATH)
+ end
+
+ Given 'I visit project source page for "8470d70"' do
+ visit tree_project_ref_path(@project, "8470d70")
+ end
+
+ Given 'I visit project tags page' do
+ visit tags_project_repository_path(@project)
+ end
+
+ Given 'I visit project commit page' do
+ visit project_commit_path(@project, ValidCommit::ID)
+ end
+
+ And 'I visit project "Shop" issues page' do
+ visit project_issues_path(Project.find_by_name("Shop"))
+ end
+
+ Given 'I visit issue page "Release 0.4"' do
+ issue = Issue.find_by_title("Release 0.4")
+ visit project_issue_path(issue.project, issue)
+ end
+
+ Given 'I visit project "Shop" labels page' do
+ visit project_labels_path(Project.find_by_name("Shop"))
+ end
+
+ Given 'I visit merge request page "Bug NS-04"' do
+ mr = MergeRequest.find_by_title("Bug NS-04")
+ visit project_merge_request_path(mr.project, mr)
+ end
+
+ And 'I visit project "Shop" merge requests page' do
+ visit project_merge_requests_path(Project.find_by_name("Shop"))
+ end
+
+ Given 'I visit project "Shop" milestones page' do
+ @project = Project.find_by_name("Shop")
+ visit project_milestones_path(@project)
+ end
+
+ Then 'I visit project "Shop" team page' do
+ visit project_team_index_path(Project.find_by_name("Shop"))
+ end
+
+ Then 'I visit project "Shop" wall page' do
+ project = Project.find_by_name("Shop")
+ visit wall_project_path(project)
+ end
+
+ Given 'I visit project wiki page' do
+ visit project_wiki_path(@project, :index)
+ end
+end
diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb
new file mode 100644
index 00000000..9b64ca59
--- /dev/null
+++ b/features/steps/shared/project.rb
@@ -0,0 +1,8 @@
+module SharedProject
+ include Spinach::DSL
+
+ And 'I own project "Shop"' do
+ @project = Factory :project, :name => "Shop"
+ @project.add_access(@user, :admin)
+ end
+end
diff --git a/features/support/env.rb b/features/support/env.rb
index b69a5fe7..9c6cef07 100644
--- a/features/support/env.rb
+++ b/features/support/env.rb
@@ -1,50 +1,27 @@
-unless ENV['CI']
- require 'simplecov'
- SimpleCov.start 'rails'
+ENV['RAILS_ENV'] = 'test'
+require './config/environment'
+
+require 'rspec'
+require 'database_cleaner'
+require 'spinach/capybara'
+
+%w(gitolite_stub stubbed_repository valid_commit).each do |f|
+ require Rails.root.join('spec', 'support', f)
end
-require 'cucumber/rails'
-require 'webmock/cucumber'
+Dir["#{Rails.root}/features/steps/shared/*.rb"].each {|file| require file}
+
+include GitoliteStub
+
WebMock.allow_net_connect!
-
-require Rails.root.join 'spec/monkeypatch'
-require Rails.root.join 'spec/factories'
-require Rails.root.join 'spec/support/login'
-require Rails.root.join 'spec/support/valid_commit'
-
-Capybara.default_selector = :css
Capybara.javascript_driver = :webkit
-# By default, any exception happening in your Rails application will bubble up
-# to Cucumber so that your scenario will fail. This is a different from how
-# your application behaves in the production environment, where an error page will
-# be rendered instead.
-#
-# Sometimes we want to override this default behaviour and allow Rails to rescue
-# exceptions and display an error page (just like when the app is running in production).
-# Typical scenarios where you want to do this is when you test your error pages.
-# There are two ways to allow Rails to rescue exceptions:
-#
-# 1) Tag your scenario (or feature) with @allow-rescue
-#
-# 2) Set the value below to true. Beware that doing this globally is not
-# recommended as it will mask a lot of errors for you!
-#
-ActionController::Base.allow_rescue = false
+DatabaseCleaner.strategy = :truncation
+Spinach.hooks.before_scenario { DatabaseCleaner.start }
+Spinach.hooks.after_scenario { DatabaseCleaner.clean }
-# Remove/comment out the lines below if your app doesn't have a database.
-# For some databases (like MongoDB and CouchDB) you may need to use :truncation instead.
-begin
- DatabaseCleaner.strategy = :transaction
-rescue NameError
- raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it."
+Spinach.hooks.before_run do
+ RSpec::Mocks::setup self
+
+ stub_gitolite!
end
-
-Cucumber::Rails::Database.javascript_strategy = :truncation
-
-require 'headless'
-
-headless = Headless.new
-headless.start
-
-require 'cucumber/rspec/doubles'
diff --git a/gitlab b/gitlab
new file mode 100755
index 00000000..acafb3f1
--- /dev/null
+++ b/gitlab
@@ -0,0 +1,75 @@
+#!/usr/bin/env ruby
+
+class GitlabCli
+ def initialize
+ @path = File.dirname(__FILE__)
+ @command = ARGV.shift
+ @mode = ARGV.shift
+ end
+
+ def execute
+ case @command
+ when 'start' then start
+ when 'stop' then stop
+ else
+ puts "-- Usage gitlab start production or gitlab stop development"
+ end
+ end
+
+ private
+
+ def start
+ case @mode
+ when 'production';
+ system(unicorn_start_cmd)
+ system(resque_start_cmd)
+ else
+ system(rails_start_cmd)
+ system(resque_dev_start_cmd)
+ end
+ end
+
+ def stop
+ case @mode
+ when 'production';
+ system(unicorn_stop_cmd)
+ else
+ system(rails_stop_cmd)
+ end
+ system(resque_stop_cmd)
+ end
+
+ def rails_start_cmd
+ "bundle exec rails s -d"
+ end
+
+ def rails_stop_cmd
+ pid = File.join(@path, "tmp/pids/server.pid")
+ "kill -QUIT `cat #{pid}`"
+ end
+
+ def unicorn_start_cmd
+ unicorn_conf = File.join(@path, "config/unicorn.rb")
+ "bundle exec unicorn_rails -c #{unicorn_conf} -E production -D"
+ end
+
+ def unicorn_stop_cmd
+ pid = File.join(@path, "/tmp/pids/unicorn.pid")
+ "kill -QUIT `cat #{pid}`"
+ end
+
+ def resque_dev_start_cmd
+ "./resque_dev.sh > /dev/null 2>&1"
+ end
+
+ def resque_start_cmd
+ "./resque.sh > /dev/null 2>&1"
+ end
+
+ def resque_stop_cmd
+ pid = File.join(@path, "tmp/pids/resque_worker.pid")
+ "kill -QUIT `cat #{pid}`"
+ end
+end
+
+GitlabCli.new.execute
diff --git a/lib/api.rb b/lib/api.rb
index 3ff3b383..2890a8cc 100644
--- a/lib/api.rb
+++ b/lib/api.rb
@@ -16,5 +16,7 @@ module Gitlab
mount Users
mount Projects
mount Issues
+ mount Milestones
+ mount Session
end
end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 96ccd87a..ee693de6 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -9,6 +9,14 @@ module Gitlab
expose :id, :email, :name, :blocked, :created_at
end
+ class UserLogin < UserBasic
+ expose :private_token
+ end
+
+ class Hook < Grape::Entity
+ expose :id, :url
+ end
+
class Project < Grape::Entity
expose :id, :code, :name, :description, :path, :default_branch
expose :owner, using: Entities::UserBasic
@@ -16,10 +24,20 @@ module Gitlab
expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at
end
+ class ProjectMember < UserBasic
+ expose :project_access, :as => :access_level do |user, options|
+ options[:project].users_projects.find_by_user_id(user.id).project_access
+ end
+ end
+
class RepoObject < Grape::Entity
expose :name, :commit
end
+ class RepoCommit < Grape::Entity
+ expose :id, :short_id, :title, :author_name, :author_email, :created_at
+ end
+
class ProjectSnippet < Grape::Entity
expose :id, :title, :file_name
expose :author, using: Entities::UserBasic
@@ -27,7 +45,9 @@ module Gitlab
end
class Milestone < Grape::Entity
- expose :id, :title, :description, :due_date, :closed, :updated_at, :created_at
+ expose :id
+ expose (:project_id) {|milestone| milestone.project.id}
+ expose :title, :description, :due_date, :closed, :updated_at, :created_at
end
class Issue < Grape::Entity
@@ -39,5 +59,9 @@ module Gitlab
expose :assignee, :author, using: Entities::UserBasic
expose :closed, :updated_at, :created_at
end
+
+ class SSHKey < Grape::Entity
+ expose :id, :title, :key
+ end
end
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index c1ea0566..14390545 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -8,14 +8,67 @@ module Gitlab
if @project ||= current_user.projects.find_by_id(params[:id]) ||
current_user.projects.find_by_code(params[:id])
else
- error!({'message' => '404 Not found'}, 404)
+ not_found!
end
@project
end
+ def paginate(object)
+ object.page(params[:page]).per(params[:per_page].to_i)
+ end
+
def authenticate!
- error!({'message' => '401 Unauthorized'}, 401) unless current_user
+ unauthorized! unless current_user
+ end
+
+ def authorize! action, subject
+ unless abilities.allowed?(current_user, action, subject)
+ forbidden!
+ end
+ end
+
+ def attributes_for_keys(keys)
+ attrs = {}
+ keys.each do |key|
+ attrs[key] = params[key] if params[key].present?
+ end
+ attrs
+ end
+
+ # error helpers
+
+ def forbidden!
+ render_api_error!('403 Forbidden', 403)
+ end
+
+ def not_found!(resource = nil)
+ message = ["404"]
+ message << resource if resource
+ message << "Not Found"
+ render_api_error!(message.join(' '), 404)
+ end
+
+ def unauthorized!
+ render_api_error!('401 Unauthorized', 401)
+ end
+
+ def not_allowed!
+ render_api_error!('Method Not Allowed', 405)
+ end
+
+ def render_api_error!(message, status)
+ error!({'message' => message}, status)
+ end
+
+ private
+
+ def abilities
+ @abilities ||= begin
+ abilities = Six.new
+ abilities << Ability
+ abilities
+ end
end
end
end
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 2abc20ad..4ee2d11f 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -9,7 +9,7 @@ module Gitlab
# Example Request:
# GET /issues
get do
- present current_user.issues, with: Entities::Issue
+ present paginate(current_user.issues), with: Entities::Issue
end
end
@@ -21,7 +21,7 @@ module Gitlab
# Example Request:
# GET /projects/:id/issues
get ":id/issues" do
- present user_project.issues, with: Entities::Issue
+ present paginate(user_project.issues), with: Entities::Issue
end
# Get a single project issue
@@ -48,19 +48,14 @@ module Gitlab
# Example Request:
# POST /projects/:id/issues
post ":id/issues" do
- @issue = user_project.issues.new(
- title: params[:title],
- description: params[:description],
- assignee_id: params[:assignee_id],
- milestone_id: params[:milestone_id],
- label_list: params[:labels]
- )
+ attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id]
+ attrs[:label_list] = params[:labels] if params[:labels].present?
+ @issue = user_project.issues.new attrs
@issue.author = current_user
-
if @issue.save
present @issue, with: Entities::Issue
else
- error!({'message' => '404 Not found'}, 404)
+ not_found!
end
end
@@ -79,23 +74,18 @@ module Gitlab
# PUT /projects/:id/issues/:issue_id
put ":id/issues/:issue_id" do
@issue = user_project.issues.find(params[:issue_id])
- parameters = {
- title: (params[:title] || @issue.title),
- description: (params[:description] || @issue.description),
- assignee_id: (params[:assignee_id] || @issue.assignee_id),
- milestone_id: (params[:milestone_id] || @issue.milestone_id),
- label_list: (params[:labels] || @issue.label_list),
- closed: (params[:closed] || @issue.closed)
- }
+ authorize! :modify_issue, @issue
- if @issue.update_attributes(parameters)
+ attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :closed]
+ attrs[:label_list] = params[:labels] if params[:labels].present?
+ if @issue.update_attributes attrs
present @issue, with: Entities::Issue
else
- error!({'message' => '404 Not found'}, 404)
+ not_found!
end
end
- # Delete a project issue
+ # Delete a project issue (deprecated)
#
# Parameters:
# id (required) - The ID or code name of a project
@@ -103,8 +93,7 @@ module Gitlab
# Example Request:
# DELETE /projects/:id/issues/:issue_id
delete ":id/issues/:issue_id" do
- @issue = user_project.issues.find(params[:issue_id])
- @issue.destroy
+ not_allowed!
end
end
end
diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb
new file mode 100644
index 00000000..f55dfd04
--- /dev/null
+++ b/lib/api/milestones.rb
@@ -0,0 +1,78 @@
+module Gitlab
+ # Milestones API
+ class Milestones < Grape::API
+ before { authenticate! }
+
+ resource :projects do
+ # Get a list of project milestones
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # Example Request:
+ # GET /projects/:id/milestones
+ get ":id/milestones" do
+ authorize! :read_milestone, user_project
+
+ present paginate(user_project.milestones), with: Entities::Milestone
+ end
+
+ # Get a single project milestone
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # milestone_id (required) - The ID of a project milestone
+ # Example Request:
+ # GET /projects/:id/milestones/:milestone_id
+ get ":id/milestones/:milestone_id" do
+ authorize! :read_milestone, user_project
+
+ @milestone = user_project.milestones.find(params[:milestone_id])
+ present @milestone, with: Entities::Milestone
+ end
+
+ # Create a new project milestone
+ #
+ # Parameters:
+ # id (required) - The ID or code name of the project
+ # title (required) - The title of the milestone
+ # description (optional) - The description of the milestone
+ # due_date (optional) - The due date of the milestone
+ # Example Request:
+ # POST /projects/:id/milestones
+ post ":id/milestones" do
+ authorize! :admin_milestone, user_project
+
+ attrs = attributes_for_keys [:title, :description, :due_date]
+ @milestone = user_project.milestones.new attrs
+ if @milestone.save
+ present @milestone, with: Entities::Milestone
+ else
+ not_found!
+ end
+ end
+
+ # Update an existing project milestone
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # milestone_id (required) - The ID of a project milestone
+ # title (optional) - The title of a milestone
+ # description (optional) - The description of a milestone
+ # due_date (optional) - The due date of a milestone
+ # closed (optional) - The status of the milestone
+ # Example Request:
+ # PUT /projects/:id/milestones/:milestone_id
+ put ":id/milestones/:milestone_id" do
+ authorize! :admin_milestone, user_project
+
+ @milestone = user_project.milestones.find(params[:milestone_id])
+ attrs = attributes_for_keys [:title, :description, :due_date, :closed]
+ if @milestone.update_attributes attrs
+ present @milestone, with: Entities::Milestone
+ else
+ not_found!
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index eb23641c..c3dc3da6 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -9,7 +9,7 @@ module Gitlab
# Example Request:
# GET /projects
get do
- @projects = current_user.projects
+ @projects = paginate current_user.projects
present @projects, with: Entities::Project
end
@@ -23,6 +23,162 @@ module Gitlab
present user_project, with: Entities::Project
end
+ # Create new project
+ #
+ # Parameters:
+ # name (required) - name for new project
+ # code (optional) - code for new project, uses project name if not set
+ # path (optional) - path for new project, uses project name if not set
+ # description (optional) - short project description
+ # default_branch (optional) - 'master' by default
+ # issues_enabled (optional) - enabled by default
+ # wall_enabled (optional) - enabled by default
+ # merge_requests_enabled (optional) - enabled by default
+ # wiki_enabled (optional) - enabled by default
+ # Example Request
+ # POST /projects
+ post do
+ params[:code] ||= params[:name]
+ params[:path] ||= params[:name]
+ attrs = attributes_for_keys [:code,
+ :path,
+ :name,
+ :description,
+ :default_branch,
+ :issues_enabled,
+ :wall_enabled,
+ :merge_requests_enabled,
+ :wiki_enabled]
+ @project = Project.create_by_user(attrs, current_user)
+ if @project.saved?
+ present @project, with: Entities::Project
+ else
+ not_found!
+ end
+ end
+
+ # Get a project team members
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # Example Request:
+ # GET /projects/:id/members
+ get ":id/members" do
+ @members = paginate user_project.users
+ present @members, with: Entities::ProjectMember, project: user_project
+ end
+
+ # Get a project team members
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # user_id (required) - The ID of a user
+ # Example Request:
+ # GET /projects/:id/members/:user_id
+ get ":id/members/:user_id" do
+ @member = user_project.users.find params[:user_id]
+ present @member, with: Entities::ProjectMember, project: user_project
+ end
+
+ # Add a new project team member
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # user_id (required) - The ID of a user
+ # access_level (required) - Project access level
+ # Example Request:
+ # POST /projects/:id/members
+ post ":id/members" do
+ authorize! :admin_project, user_project
+ users_project = user_project.users_projects.new(
+ user_id: params[:user_id],
+ project_access: params[:access_level]
+ )
+
+ if users_project.save
+ @member = users_project.user
+ present @member, with: Entities::ProjectMember, project: user_project
+ else
+ not_found!
+ end
+ end
+
+ # Update project team member
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # user_id (required) - The ID of a team member
+ # access_level (required) - Project access level
+ # Example Request:
+ # PUT /projects/:id/members/:user_id
+ put ":id/members/:user_id" do
+ authorize! :admin_project, user_project
+ users_project = user_project.users_projects.find_by_user_id params[:user_id]
+
+ if users_project.update_attributes(project_access: params[:access_level])
+ @member = users_project.user
+ present @member, with: Entities::ProjectMember, project: user_project
+ else
+ not_found!
+ end
+ end
+
+ # Remove a team member from project
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # user_id (required) - The ID of a team member
+ # Example Request:
+ # DELETE /projects/:id/members/:user_id
+ delete ":id/members/:user_id" do
+ authorize! :admin_project, user_project
+ users_project = user_project.users_projects.find_by_user_id params[:user_id]
+ users_project.destroy
+ end
+
+ # Get project hooks
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # Example Request:
+ # GET /projects/:id/hooks
+ get ":id/hooks" do
+ authorize! :admin_project, user_project
+ @hooks = paginate user_project.hooks
+ present @hooks, with: Entities::Hook
+ end
+
+ # Add hook to project
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # url (required) - The hook URL
+ # Example Request:
+ # POST /projects/:id/hooks
+ post ":id/hooks" do
+ authorize! :admin_project, user_project
+ @hook = user_project.hooks.new({"url" => params[:url]})
+ if @hook.save
+ present @hook, with: Entities::Hook
+ else
+ error!({'message' => '404 Not found'}, 404)
+ end
+ end
+
+ # Delete project hook
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # hook_id (required) - The ID of hook to delete
+ # Example Request:
+ # DELETE /projects/:id/hooks
+ delete ":id/hooks" do
+ authorize! :admin_project, user_project
+ @hook = user_project.hooks.find(params[:hook_id])
+ @hook.destroy
+ nil
+ end
+
# Get a project repository branches
#
# Parameters:
@@ -55,6 +211,24 @@ module Gitlab
present user_project.repo.tags.sort_by(&:name).reverse, with: Entities::RepoObject
end
+ # Get a project repository commits
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # ref_name (optional) - The name of a repository branch or tag
+ # Example Request:
+ # GET /projects/:id/repository/commits
+ get ":id/repository/commits" do
+ authorize! :download_code, user_project
+
+ page = params[:page] || 0
+ per_page = params[:per_page] || 20
+ ref = params[:ref_name] || user_project.try(:default_branch) || 'master'
+
+ commits = user_project.commits(ref, nil, per_page, page * per_page)
+ present CommitDecorator.decorate(commits), with: Entities::RepoCommit
+ end
+
# Get a project snippet
#
# Parameters:
@@ -78,18 +252,18 @@ module Gitlab
# Example Request:
# POST /projects/:id/snippets
post ":id/snippets" do
- @snippet = user_project.snippets.new(
- title: params[:title],
- file_name: params[:file_name],
- expires_at: params[:lifetime],
- content: params[:code]
- )
+ authorize! :write_snippet, user_project
+
+ attrs = attributes_for_keys [:title, :file_name]
+ attrs[:expires_at] = params[:lifetime] if params[:lifetime].present?
+ attrs[:content] = params[:code] if params[:code].present?
+ @snippet = user_project.snippets.new attrs
@snippet.author = current_user
if @snippet.save
present @snippet, with: Entities::ProjectSnippet
else
- error!({'message' => '404 Not found'}, 404)
+ not_found!
end
end
@@ -106,17 +280,16 @@ module Gitlab
# PUT /projects/:id/snippets/:snippet_id
put ":id/snippets/:snippet_id" do
@snippet = user_project.snippets.find(params[:snippet_id])
- parameters = {
- title: (params[:title] || @snippet.title),
- file_name: (params[:file_name] || @snippet.file_name),
- expires_at: (params[:lifetime] || @snippet.expires_at),
- content: (params[:code] || @snippet.content)
- }
+ authorize! :modify_snippet, @snippet
- if @snippet.update_attributes(parameters)
+ attrs = attributes_for_keys [:title, :file_name]
+ attrs[:expires_at] = params[:lifetime] if params[:lifetime].present?
+ attrs[:content] = params[:code] if params[:code].present?
+
+ if @snippet.update_attributes attrs
present @snippet, with: Entities::ProjectSnippet
else
- error!({'message' => '404 Not found'}, 404)
+ not_found!
end
end
@@ -129,6 +302,8 @@ module Gitlab
# DELETE /projects/:id/snippets/:snippet_id
delete ":id/snippets/:snippet_id" do
@snippet = user_project.snippets.find(params[:snippet_id])
+ authorize! :modify_snippet, @snippet
+
@snippet.destroy
end
@@ -154,13 +329,15 @@ module Gitlab
# Example Request:
# GET /projects/:id/repository/commits/:sha/blob
get ":id/repository/commits/:sha/blob" do
+ authorize! :download_code, user_project
+
ref = params[:sha]
commit = user_project.commit ref
- error!('404 Commit Not Found', 404) unless commit
+ not_found! "Commit" unless commit
tree = Tree.new commit.tree, user_project, ref, params[:filepath]
- error!('404 File Not Found', 404) unless tree.try(:tree)
+ not_found! "File" unless tree.try(:tree)
if tree.text?
encoding = Gitlab::Encode.detect_encoding(tree.data)
diff --git a/lib/api/session.rb b/lib/api/session.rb
new file mode 100644
index 00000000..b4050160
--- /dev/null
+++ b/lib/api/session.rb
@@ -0,0 +1,20 @@
+module Gitlab
+ # Users API
+ class Session < Grape::API
+ # Login to get token
+ #
+ # Example Request:
+ # POST /session
+ post "/session" do
+ resource = User.find_for_database_authentication(email: params[:email])
+
+ return unauthorized! unless resource
+
+ if resource.valid_password?(params[:password])
+ present resource, with: Entities::UserLogin
+ else
+ unauthorized!
+ end
+ end
+ end
+end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 81cb2a0e..0ca8fb2a 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -9,7 +9,7 @@ module Gitlab
# Example Request:
# GET /users
get do
- @users = User.all
+ @users = paginate User
present @users, with: Entities::User
end
@@ -25,12 +25,59 @@ module Gitlab
end
end
- # Get currently authenticated user
- #
- # Example Request:
- # GET /user
- get "/user" do
- present @current_user, with: Entities::User
+ resource :user do
+ # Get currently authenticated user
+ #
+ # Example Request:
+ # GET /user
+ get do
+ present @current_user, with: Entities::User
+ end
+
+ # Get currently authenticated user's keys
+ #
+ # Example Request:
+ # GET /user/keys
+ get "keys" do
+ present current_user.keys, with: Entities::SSHKey
+ end
+
+ # Get single key owned by currently authenticated user
+ #
+ # Example Request:
+ # GET /user/keys/:id
+ get "keys/:id" do
+ key = current_user.keys.find params[:id]
+ present key, with: Entities::SSHKey
+ end
+
+ # Add new ssh key to currently authenticated user
+ #
+ # Parameters:
+ # key (required) - New SSH Key
+ # title (required) - New SSH Key's title
+ # Example Request:
+ # POST /user/keys
+ post "keys" do
+ attrs = attributes_for_keys [:title, :key]
+ key = current_user.keys.new attrs
+ if key.save
+ present key, with: Entities::SSHKey
+ else
+ not_found!
+ end
+ end
+
+ # Delete existed ssh key of currently authenticated user
+ #
+ # Parameters:
+ # id (required) - SSH Key ID
+ # Example Request:
+ # DELETE /user/keys/:id
+ delete "keys/:id" do
+ key = current_user.keys.find params[:id]
+ key.delete
+ end
end
end
end
diff --git a/lib/gitlab/app_logger.rb b/lib/gitlab/app_logger.rb
new file mode 100644
index 00000000..8e4717b4
--- /dev/null
+++ b/lib/gitlab/app_logger.rb
@@ -0,0 +1,11 @@
+module Gitlab
+ class AppLogger < Gitlab::Logger
+ def self.file_name
+ 'application.log'
+ end
+
+ def format_message(severity, timestamp, progname, msg)
+ "#{timestamp.to_s(:long)}: #{msg}\n"
+ end
+ end
+end
diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb
new file mode 100644
index 00000000..90bd5d74
--- /dev/null
+++ b/lib/gitlab/auth.rb
@@ -0,0 +1,66 @@
+module Gitlab
+ class Auth
+ def find_for_ldap_auth(auth, signed_in_resource = nil)
+ uid = auth.info.uid
+ provider = auth.provider
+ email = auth.info.email.downcase unless auth.info.email.nil?
+ raise OmniAuth::Error, "LDAP accounts must provide an uid and email address" if uid.nil? or email.nil?
+
+ if @user = User.find_by_extern_uid_and_provider(uid, provider)
+ @user
+ elsif @user = User.find_by_email(email)
+ log.info "Updating legacy LDAP user #{email} with extern_uid => #{uid}"
+ @user.update_attributes(:extern_uid => uid, :provider => provider)
+ @user
+ else
+ create_from_omniauth(auth, true)
+ end
+ end
+
+ def create_from_omniauth(auth, ldap = false)
+ provider = auth.provider
+ uid = auth.info.uid || auth.uid
+ name = auth.info.name.force_encoding("utf-8")
+ email = auth.info.email.downcase unless auth.info.email.nil?
+
+ ldap_prefix = ldap ? '(LDAP) ' : ''
+ raise OmniAuth::Error, "#{ldap_prefix}#{provider} does not provide an email"\
+ " address" if auth.info.email.blank?
+
+ log.info "#{ldap_prefix}Creating user from #{provider} login"\
+ " {uid => #{uid}, name => #{name}, email => #{email}}"
+ password = Devise.friendly_token[0, 8].downcase
+ @user = User.new(
+ extern_uid: uid,
+ provider: provider,
+ name: name,
+ email: email,
+ password: password,
+ password_confirmation: password,
+ projects_limit: Gitlab.config.default_projects_limit,
+ )
+ if Gitlab.config.omniauth['block_auto_created_users'] && !ldap
+ @user.blocked = true
+ end
+ @user.save!
+ @user
+ end
+
+ def find_or_new_for_omniauth(auth)
+ provider, uid = auth.provider, auth.uid
+
+ if @user = User.find_by_provider_and_extern_uid(provider, uid)
+ @user
+ else
+ if Gitlab.config.omniauth['allow_single_sign_on']
+ @user = create_from_omniauth(auth)
+ @user
+ end
+ end
+ end
+
+ def log
+ Gitlab::AppLogger
+ end
+ end
+end
diff --git a/lib/gitlab/backend/gitolite.rb b/lib/gitlab/backend/gitolite.rb
new file mode 100644
index 00000000..fe5dcef4
--- /dev/null
+++ b/lib/gitlab/backend/gitolite.rb
@@ -0,0 +1,43 @@
+require_relative 'gitolite_config'
+
+module Gitlab
+ class Gitolite
+ class AccessDenied < StandardError; end
+
+ def config
+ Gitlab::GitoliteConfig.new
+ end
+
+ def set_key key_id, key_content, projects
+ config.apply do |config|
+ config.write_key(key_id, key_content)
+ config.update_projects(projects)
+ end
+ end
+
+ def remove_key key_id, projects
+ config.apply do |config|
+ config.rm_key(key_id)
+ config.update_projects(projects)
+ end
+ end
+
+ def update_repository project
+ config.update_project!(project.path, project)
+ end
+
+ def remove_repository project
+ config.destroy_project!(project)
+ end
+
+ def url_to_repo path
+ Gitlab.config.ssh_path + "#{path}.git"
+ end
+
+ def enable_automerge
+ config.admin_all_repo!
+ end
+
+ alias_method :create_repository, :update_repository
+ end
+end
diff --git a/lib/gitlab/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb
new file mode 100644
index 00000000..f51e8efc
--- /dev/null
+++ b/lib/gitlab/backend/gitolite_config.rb
@@ -0,0 +1,196 @@
+require 'gitolite'
+require 'timeout'
+require 'fileutils'
+
+module Gitlab
+ class GitoliteConfig
+ class PullError < StandardError; end
+ class PushError < StandardError; end
+
+ attr_reader :config_tmp_dir, :ga_repo, :conf
+
+ def config_tmp_dir
+ @config_tmp_dir ||= File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}")
+ end
+
+ def ga_repo
+ @ga_repo ||= ::Gitolite::GitoliteAdmin.new(File.join(config_tmp_dir,'gitolite'))
+ end
+
+ def apply
+ Timeout::timeout(30) do
+ File.open(File.join(Rails.root, 'tmp', "gitlabhq-gitolite.lock"), "w+") do |f|
+ begin
+ # Set exclusive lock
+ # to prevent race condition
+ f.flock(File::LOCK_EX)
+
+ # Pull gitolite-admin repo
+ # in tmp dir before do any changes
+ pull(config_tmp_dir)
+
+ # Build ga_repo object and @conf
+ # to access gitolite-admin configuration
+ @conf = ga_repo.config
+
+ # Do any changes
+ # in gitolite-admin
+ # config here
+ yield(self)
+
+ # Save changes in
+ # gitolite-admin repo
+ # before pusht it
+ ga_repo.save
+
+ # Push gitolite-admin repo
+ # to apply all changes
+ push(config_tmp_dir)
+
+ # Remove tmp dir
+ # wiith gitolite-admin
+ FileUtils.rm_rf(config_tmp_dir)
+ ensure
+ # unlock so other task cann access
+ # gitolite configuration
+ f.flock(File::LOCK_UN)
+ end
+ end
+ end
+ rescue PullError => ex
+ log("Pull error -> " + ex.message)
+ raise Gitolite::AccessDenied, ex.message
+
+ rescue PushError => ex
+ log("Push error -> " + " " + ex.message)
+ raise Gitolite::AccessDenied, ex.message
+
+ rescue Exception => ex
+ log(ex.class.name + " " + ex.message)
+ raise Gitolite::AccessDenied.new("gitolite timeout")
+ end
+
+ def log message
+ Gitlab::GitLogger.error(message)
+ end
+
+ def destroy_project(project)
+ FileUtils.rm_rf(project.path_to_repo)
+ conf.rm_repo(project.path)
+ end
+
+ def destroy_project!(project)
+ apply do |config|
+ config.destroy_project(project)
+ end
+ end
+
+ def write_key(id, key)
+ File.open(File.join(config_tmp_dir, 'gitolite/keydir',"#{id}.pub"), 'w') do |f|
+ f.write(key.gsub(/\n/,''))
+ end
+ end
+
+ def rm_key(user)
+ File.unlink(File.join(config_tmp_dir, 'gitolite/keydir',"#{user}.pub"))
+ `cd #{File.join(config_tmp_dir,'gitolite')} ; git rm keydir/#{user}.pub`
+ end
+
+ # update or create
+ def update_project(repo_name, project)
+ repo = update_project_config(project, conf)
+ conf.add_repo(repo, true)
+ end
+
+ def update_project!(repo_name, project)
+ apply do |config|
+ config.update_project(repo_name, project)
+ end
+ end
+
+ # Updates many projects and uses project.path as the repo path
+ # An order of magnitude faster than update_project
+ def update_projects(projects)
+ projects.each do |project|
+ repo = update_project_config(project, conf)
+ conf.add_repo(repo, true)
+ end
+ end
+
+ def update_project_config(project, conf)
+ repo_name = project.path
+
+ repo = if conf.has_repo?(repo_name)
+ conf.get_repo(repo_name)
+ else
+ ::Gitolite::Config::Repo.new(repo_name)
+ end
+
+ name_readers = project.repository_readers
+ name_writers = project.repository_writers
+ name_masters = project.repository_masters
+
+ pr_br = project.protected_branches.map(&:name).join("$ ")
+
+ repo.clean_permissions
+
+ # Deny access to protected branches for writers
+ unless name_writers.blank? || pr_br.blank?
+ repo.add_permission("-", pr_br.strip + "$ ", name_writers)
+ end
+
+ # Add read permissions
+ repo.add_permission("R", "", name_readers) unless name_readers.blank?
+
+ # Add write permissions
+ repo.add_permission("RW+", "", name_writers) unless name_writers.blank?
+ repo.add_permission("RW+", "", name_masters) unless name_masters.blank?
+
+ repo
+ end
+
+ # Enable access to all repos for gitolite admin.
+ # We use it for accept merge request feature
+ def admin_all_repo
+ owner_name = Gitlab.config.gitolite_admin_key
+
+ # @ALL repos premission for gitolite owner
+ repo_name = "@all"
+ repo = if conf.has_repo?(repo_name)
+ conf.get_repo(repo_name)
+ else
+ ::Gitolite::Config::Repo.new(repo_name)
+ end
+
+ repo.add_permission("RW+", "", owner_name)
+ conf.add_repo(repo, true)
+ end
+
+ def admin_all_repo!
+ apply { |config| config.admin_all_repo }
+ end
+
+ private
+
+ def pull tmp_dir
+ Dir.mkdir tmp_dir
+ `git clone #{Gitlab.config.gitolite_admin_uri} #{tmp_dir}/gitolite`
+
+ unless File.exists?(File.join(tmp_dir, 'gitolite', 'conf', 'gitolite.conf'))
+ raise PullError, "unable to clone gitolite-admin repo"
+ end
+ end
+
+ def push tmp_dir
+ Dir.chdir(File.join(tmp_dir, "gitolite"))
+ system('git add -A')
+ system('git commit -am "GitLab"')
+ if system('git push')
+ Dir.chdir(Rails.root)
+ else
+ raise PushError, "unable to push gitolite-admin repo"
+ end
+ end
+ end
+end
+
diff --git a/config/initializers/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb
similarity index 64%
rename from config/initializers/grack_auth.rb
rename to lib/gitlab/backend/grack_auth.rb
index 5995b873..43a75cc3 100644
--- a/config/initializers/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -12,21 +12,22 @@ module Grack
# Pass Gitolite update hook
ENV['GL_BYPASS_UPDATE_HOOK'] = "true"
- # Need this patch because the rails mount
- @env['PATH_INFO'] = @env['REQUEST_PATH']
+ # Need this patch due to the rails mount
+ @env['PATH_INFO'] = @request.path
+ @env['SCRIPT_NAME'] = ""
# Find project by PATH_INFO from env
- if m = /^\/([\w-]+).git/.match(@env['PATH_INFO']).to_a
+ if m = /^\/([\w-]+).git/.match(@request.path_info).to_a
return false unless project = Project.find_by_path(m.last)
end
# Git upload and receive
- if @env['REQUEST_METHOD'] == 'GET'
+ if @request.get?
true
- elsif @env['REQUEST_METHOD'] == 'POST'
- if @env['REQUEST_URI'].end_with?('git-upload-pack')
+ elsif @request.post?
+ if @request.path_info.end_with?('git-upload-pack')
return project.dev_access_for?(user)
- elsif @env['REQUEST_URI'].end_with?('git-receive-pack')
+ elsif @request.path_info.end_with?('git-receive-pack')
if project.protected_branches.map(&:name).include?(current_ref)
project.master_access_for?(user)
else
@@ -42,13 +43,13 @@ module Grack
def current_ref
if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/
- input = Zlib::GzipReader.new(@request.body).string
+ input = Zlib::GzipReader.new(@request.body).read
else
- input = @request.body.string
+ input = @request.body.read
end
-
- oldrev, newrev, ref = input.split(' ')
- /refs\/heads\/([\w-]+)/.match(ref).to_a.last
+ # Need to reset seek point
+ @request.body.rewind
+ /refs\/heads\/([\w-]+)/.match(input).to_a.first
end
end# Auth
end# Grack
diff --git a/lib/gitlab/git_host.rb b/lib/gitlab/git_host.rb
deleted file mode 100644
index 76b2c7b1..00000000
--- a/lib/gitlab/git_host.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require File.join(Rails.root, "lib", "gitlab", "gitolite")
-
-module Gitlab
- class GitHost
- def self.system
- Gitlab::Gitolite
- end
-
- def self.admin_uri
- Gitlab.config.git_host.admin_uri
- end
-
- def self.url_to_repo(path)
- Gitlab.config.ssh_path + "#{path}.git"
- end
- end
-end
diff --git a/lib/gitlab/git_logger.rb b/lib/gitlab/git_logger.rb
new file mode 100644
index 00000000..fbfed205
--- /dev/null
+++ b/lib/gitlab/git_logger.rb
@@ -0,0 +1,11 @@
+module Gitlab
+ class GitLogger < Gitlab::Logger
+ def self.file_name
+ 'githost.log'
+ end
+
+ def format_message(severity, timestamp, progname, msg)
+ "#{timestamp.to_s(:long)} -> #{severity} -> #{msg}\n"
+ end
+ end
+end
diff --git a/lib/gitlab/gitolite.rb b/lib/gitlab/gitolite.rb
deleted file mode 100644
index e82f9e62..00000000
--- a/lib/gitlab/gitolite.rb
+++ /dev/null
@@ -1,157 +0,0 @@
-require 'gitolite'
-require 'timeout'
-require 'fileutils'
-
-module Gitlab
- class Gitolite
- class AccessDenied < StandardError; end
-
- def self.update_project(path, project)
- self.new.configure { |git| git.update_project(path, project) }
- end
-
- def self.destroy_project(project)
- self.new.configure { |git| git.destroy_project(project) }
- end
-
- def pull
- # create tmp dir
- @local_dir = File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}")
- Dir.mkdir @local_dir
-
- `git clone #{GitHost.admin_uri} #{@local_dir}/gitolite`
- end
-
- def push
- Dir.chdir(File.join(@local_dir, "gitolite"))
- `git add -A`
- `git commit -am "Gitlab"`
- `git push`
- Dir.chdir(Rails.root)
-
- FileUtils.rm_rf(@local_dir)
- end
-
- def configure
- Timeout::timeout(30) do
- File.open(File.join(Rails.root, 'tmp', "gitlabhq-gitolite.lock"), "w+") do |f|
- begin
- f.flock(File::LOCK_EX)
- pull
- yield(self)
- push
- ensure
- f.flock(File::LOCK_UN)
- end
- end
- end
- rescue Exception => ex
- Gitlab::Logger.error(ex.message)
- raise Gitolite::AccessDenied.new("gitolite timeout")
- end
-
- def destroy_project(project)
- FileUtils.rm_rf(project.path_to_repo)
-
- ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite'))
- conf = ga_repo.config
- conf.rm_repo(project.path)
- ga_repo.save
- end
-
- #update or create
- def update_keys(user, key)
- File.open(File.join(@local_dir, 'gitolite/keydir',"#{user}.pub"), 'w') {|f| f.write(key.gsub(/\n/,'')) }
- end
-
- def delete_key(user)
- File.unlink(File.join(@local_dir, 'gitolite/keydir',"#{user}.pub"))
- `cd #{File.join(@local_dir,'gitolite')} ; git rm keydir/#{user}.pub`
- end
-
- # update or create
- def update_project(repo_name, project)
- ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite'))
- conf = ga_repo.config
- repo = update_project_config(project, conf)
- conf.add_repo(repo, true)
-
- ga_repo.save
- end
-
- # Updates many projects and uses project.path as the repo path
- # An order of magnitude faster than update_project
- def update_projects(projects)
- ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite'))
- conf = ga_repo.config
-
- projects.each do |project|
- repo = update_project_config(project, conf)
- conf.add_repo(repo, true)
- end
-
- ga_repo.save
- end
-
- def update_project_config(project, conf)
- repo_name = project.path
-
- repo = if conf.has_repo?(repo_name)
- conf.get_repo(repo_name)
- else
- ::Gitolite::Config::Repo.new(repo_name)
- end
-
- name_readers = project.repository_readers
- name_writers = project.repository_writers
- name_masters = project.repository_masters
-
- pr_br = project.protected_branches.map(&:name).join(" ")
-
- repo.clean_permissions
-
- # Deny access to protected branches for writers
- unless name_writers.blank? || pr_br.blank?
- repo.add_permission("-", pr_br, name_writers)
- end
-
- # Add read permissions
- repo.add_permission("R", "", name_readers) unless name_readers.blank?
-
- # Add write permissions
- repo.add_permission("RW+", "", name_writers) unless name_writers.blank?
- repo.add_permission("RW+", "", name_masters) unless name_masters.blank?
-
- repo
- end
-
- def admin_all_repo
- ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite'))
- conf = ga_repo.config
- owner_name = ""
-
- # Read gitolite-admin user
- #
- begin
- repo = conf.get_repo("gitolite-admin")
- owner_name = repo.permissions[0]["RW+"][""][0]
- raise StandardError if owner_name.blank?
- rescue => ex
- puts "Can't determine gitolite-admin owner".red
- raise StandardError
- end
-
- # @ALL repos premission for gitolite owner
- repo_name = "@all"
- repo = if conf.has_repo?(repo_name)
- conf.get_repo(repo_name)
- else
- ::Gitolite::Config::Repo.new(repo_name)
- end
-
- repo.add_permission("RW+", "", owner_name)
- conf.add_repo(repo, true)
- ga_repo.save
- end
- end
-end
diff --git a/lib/gitlab/graph_commit.rb b/lib/gitlab/graph_commit.rb
index b9859d79..d3668a99 100644
--- a/lib/gitlab/graph_commit.rb
+++ b/lib/gitlab/graph_commit.rb
@@ -5,6 +5,8 @@ module Gitlab
attr_accessor :time, :space
attr_accessor :refs
+ include ActionView::Helpers::TagHelper
+
def self.to_graph(project)
@repo = project.repo
commits = Grit::Commit.find_all(@repo, nil, {max_count: 650})
@@ -164,7 +166,7 @@ module Gitlab
h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil?
h[:id] = sha
h[:date] = date
- h[:message] = Gitlab::Encode.utf8(message)
+ h[:message] = escape_once(Gitlab::Encode.utf8(message))
h[:login] = author.email
h
end
diff --git a/lib/gitlab/logger.rb b/lib/gitlab/logger.rb
index c3a19e71..9405163d 100644
--- a/lib/gitlab/logger.rb
+++ b/lib/gitlab/logger.rb
@@ -9,17 +9,13 @@ module Gitlab
end
def self.read_latest
- path = Rails.root.join("log/githost.log")
+ path = Rails.root.join("log", file_name)
self.build unless File.exist?(path)
logs = File.read(path).split("\n")
end
def self.build
- new(File.join(Rails.root, "log/githost.log"))
+ new(File.join(Rails.root, "log", file_name))
end
-
- def format_message(severity, timestamp, progname, msg)
- "#{timestamp.to_s(:long)} -> #{severity} -> #{msg}\n"
- end
end
end
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index 75fa835d..9201003e 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -1,7 +1,8 @@
module Gitlab
- # Custom parser for Gitlab-flavored Markdown
+ # Custom parser for GitLab-flavored Markdown
#
- # It replaces references in the text with links to the appropriate items in Gitlab.
+ # It replaces references in the text with links to the appropriate items in
+ # GitLab.
#
# Supported reference formats are:
# * @foo for team members
@@ -10,44 +11,99 @@ module Gitlab
# * $123 for snippets
# * 123456 for commits
#
+ # It also parses Emoji codes to insert images. See
+ # http://www.emoji-cheat-sheet.com/ for a list of the supported icons.
+ #
# Examples
#
- # >> m = Markdown.new(...)
- #
- # >> m.parse("Hey @david, can you fix this?")
+ # >> gfm("Hey @david, can you fix this?")
# => "Hey @david, can you fix this?"
#
- # >> m.parse("Commit 35d5f7c closes #1234")
+ # >> gfm("Commit 35d5f7c closes #1234")
# => "Commit 35d5f7c closes #1234"
- class Markdown
- include Rails.application.routes.url_helpers
- include ActionView::Helpers
-
+ #
+ # >> gfm(":trollface:")
+ # => ".*?|
.*?
}m) do |match|
+ md5 = Digest::MD5.hexdigest(match)
+ extractions[md5] = match
+ "{gfm-extraction-#{md5}}"
+ end
+
+ # TODO: add popups with additional information
+
+ text = parse(text)
+
+ # Insert pre block extractions
+ text.gsub!(/\{gfm-extraction-(\h{32})\}/) do
+ extractions[$1]
+ end
+
+ sanitize text.html_safe, attributes: ActionView::Base.sanitized_allowed_attributes + %w(id class)
end
+ private
+
+ # Private: Parses text for references and emoji
+ #
+ # text - Text to parse
+ #
+ # Note: reference links will only be generated if @project is set
+ #
+ # Returns parsed text
def parse(text)
- text.gsub(REFERENCE_PATTERN) do |match|
+ parse_references(text) if @project
+ parse_emoji(text)
+
+ text
+ end
+
+ def parse_references(text)
+ # parse reference links
+ text.gsub!(REFERENCE_PATTERN) do |match|
prefix = $1 || ''
reference = $2
identifier = $3 || $4 || $5
suffix = $6 || ''
- if ref_link = reference_link(reference, identifier)
+ # Avoid HTML entities
+ if prefix.ends_with?('&') || suffix.starts_with?(';')
+ match
+ elsif ref_link = reference_link(reference, identifier)
prefix + ref_link + suffix
else
match
@@ -55,7 +111,25 @@ module Gitlab
end
end
- private
+ def parse_emoji(text)
+ # parse emoji
+ text.gsub!(EMOJI_PATTERN) do |match|
+ if valid_emoji?($2)
+ image_tag("emoji/#{$2}.png", size: "20x20", class: 'emoji', title: $1, alt: $1)
+ else
+ match
+ end
+ end
+ end
+
+ # Private: Checks if an emoji icon exists in the image asset directory
+ #
+ # emoji - Identifier of the emoji as a string (e.g., "+1", "heart")
+ #
+ # Returns boolean
+ def valid_emoji?(emoji)
+ File.exists?(Rails.root.join('app', 'assets', 'images', 'emoji', "#{emoji}.png"))
+ end
# Private: Dispatches to a dedicated processing method based on reference
#
@@ -100,7 +174,7 @@ module Gitlab
def reference_commit(identifier)
if commit = @project.commit(identifier)
- link_to(identifier, project_commit_path(@project, id: commit.id), html_options.merge(title: "Commit: #{commit.author_name} - #{CommitDecorator.new(commit).title}", class: "gfm gfm-commit #{html_options[:class]}"))
+ link_to(identifier, project_commit_path(@project, id: commit.id), html_options.merge(title: CommitDecorator.new(commit).link_title, class: "gfm gfm-commit #{html_options[:class]}"))
end
end
end
diff --git a/lib/gitlab/merge.rb b/lib/gitlab/merge.rb
index 134695ce..18013574 100644
--- a/lib/gitlab/merge.rb
+++ b/lib/gitlab/merge.rb
@@ -21,8 +21,7 @@ module Gitlab
if output =~ /CONFLICT/
false
else
- repo.git.push({}, "origin", merge_request.target_branch)
- true
+ !!repo.git.push({}, "origin", merge_request.target_branch)
end
end
end
diff --git a/lib/hooks/post-receive b/lib/hooks/post-receive
index d38bd13e..a4fa9f1c 100755
--- a/lib/hooks/post-receive
+++ b/lib/hooks/post-receive
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
-# This file was placed here by Gitlab. It makes sure that your pushed commits
+# This file was placed here by GitLab. It makes sure that your pushed commits
# will be processed properly.
while read oldrev newrev ref
diff --git a/lib/tasks/bulk_add_permission.rake b/lib/tasks/bulk_add_permission.rake
new file mode 100644
index 00000000..55797825
--- /dev/null
+++ b/lib/tasks/bulk_add_permission.rake
@@ -0,0 +1,26 @@
+desc "Add all users to all projects, system administratos are added as masters"
+task :add_users_to_project_teams => :environment do |t, args|
+ users = User.find_all_by_admin(false, :select => 'id').map(&:id)
+ admins = User.find_all_by_admin(true, :select => 'id').map(&:id)
+
+ users.each do |user|
+ puts "#{user}"
+ end
+
+ Project.all.each do |project|
+ puts "Importing #{users.length} users into #{project.path}"
+ UsersProject.bulk_import(project, users, UsersProject::DEVELOPER)
+ puts "Importing #{admins.length} admins into #{project.path}"
+ UsersProject.bulk_import(project, admins, UsersProject::MASTER)
+ end
+end
+
+desc "Add user to as a developer to all projects"
+task :add_user_to_project_teams, [:email] => :environment do |t, args|
+ user_email = args.email
+ user = User.find_by_email(user_email)
+
+ project_ids = Project.all.map(&:id)
+
+ UsersProject.user_bulk_import(user,project_ids,UsersProject::DEVELOPER)
+end
diff --git a/lib/tasks/bulk_import.rake b/lib/tasks/bulk_import.rake
index 607250f1..edb4a599 100644
--- a/lib/tasks/bulk_import.rake
+++ b/lib/tasks/bulk_import.rake
@@ -1,11 +1,10 @@
-IMPORT_DIRECTORY = 'import_projects'
-REPOSITORY_DIRECTORY = '/home/git/repositories'
-desc "Imports existing Git repos into new projects from the import_projects folder"
-task :import_projects, [:email] => :environment do |t, args|
+desc "Imports existing Git repos from a directory into new projects in git_base_path"
+task :import_projects, [:directory,:email] => :environment do |t, args|
user_email = args.email
- repos_to_import = Dir.glob("#{IMPORT_DIRECTORY}/*")
-
+ import_directory = args.directory
+ repos_to_import = Dir.glob("#{import_directory}/*")
+ git_base_path = Gitlab.config.git_base_path
puts "Found #{repos_to_import.length} repos to import"
imported_count = 0
@@ -13,11 +12,9 @@ task :import_projects, [:email] => :environment do |t, args|
failed_count = 0
repos_to_import.each do |repo_path|
repo_name = File.basename repo_path
- repo_full_path = File.join(Rails.root, repo_path)
puts " Processing #{repo_name}"
-
- clone_path = "#{REPOSITORY_DIRECTORY}/#{repo_name}.git"
+ clone_path = "#{git_base_path}#{repo_name}.git"
if Dir.exists? clone_path
if Project.find_by_code(repo_name)
@@ -29,7 +26,7 @@ task :import_projects, [:email] => :environment do |t, args|
end
else
# Clone the repo
- unless clone_bare_repo_as_git(repo_full_path, clone_path)
+ unless clone_bare_repo_as_git(repo_path, clone_path)
failed_count += 1
next
end
@@ -47,14 +44,17 @@ task :import_projects, [:email] => :environment do |t, args|
puts "Finished importing #{imported_count} projects (skipped #{skipped_count}, failed #{failed_count})."
end
-# Clones a repo as bare git repo using the git user
+# Clones a repo as bare git repo using the git_user
def clone_bare_repo_as_git(existing_path, new_path)
+ git_user = Gitlab.config.ssh_user
begin
- sh "sudo -u git -i git clone --bare '#{existing_path}' #{new_path}"
+ sh "sudo -u #{git_user} -i git clone --bare '#{existing_path}' #{new_path}"
true
- rescue
+ rescue Exception=> msg
puts " ERROR: Faild to clone #{existing_path} to #{new_path}"
- false
+ puts " Make sure #{git_user} can reach #{existing_path}"
+ puts " Exception-MSG: #{msg}"
+ false
end
end
diff --git a/lib/tasks/cucumber.rake b/lib/tasks/cucumber.rake
deleted file mode 100644
index 83f79471..00000000
--- a/lib/tasks/cucumber.rake
+++ /dev/null
@@ -1,65 +0,0 @@
-# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
-# It is recommended to regenerate this file in the future when you upgrade to a
-# newer version of cucumber-rails. Consider adding your own code to a new file
-# instead of editing this one. Cucumber will automatically load all features/**/*.rb
-# files.
-
-
-unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks
-
-vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
-$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil?
-
-begin
- require 'cucumber/rake/task'
-
- namespace :cucumber do
- Cucumber::Rake::Task.new({:ok => 'db:test:prepare'}, 'Run features that should pass') do |t|
- t.binary = vendored_cucumber_bin # If nil, the gem's binary is used.
- t.fork = true # You may get faster startup if you set this to false
- t.profile = 'default'
- end
-
- Cucumber::Rake::Task.new({:wip => 'db:test:prepare'}, 'Run features that are being worked on') do |t|
- t.binary = vendored_cucumber_bin
- t.fork = true # You may get faster startup if you set this to false
- t.profile = 'wip'
- end
-
- Cucumber::Rake::Task.new({:rerun => 'db:test:prepare'}, 'Record failing features and run only them if any exist') do |t|
- t.binary = vendored_cucumber_bin
- t.fork = true # You may get faster startup if you set this to false
- t.profile = 'rerun'
- end
-
- desc 'Run all features'
- task :all => [:ok, :wip]
-
- task :statsetup do
- require 'rails/code_statistics'
- ::STATS_DIRECTORIES << %w(Cucumber\ features features) if File.exist?('features')
- ::CodeStatistics::TEST_TYPES << "Cucumber features" if File.exist?('features')
- end
- end
- desc 'Alias for cucumber:ok'
- task :cucumber => 'cucumber:ok'
-
- task :default => :cucumber
-
- task :features => :cucumber do
- STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***"
- end
-
- # In case we don't have ActiveRecord, append a no-op task that we can depend upon.
- task 'db:test:prepare' do
- end
-
- task :stats => 'cucumber:statsetup'
-rescue LoadError
- desc 'cucumber rake task not available (cucumber not installed)'
- task :cucumber do
- abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
- end
-end
-
-end
diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake
index d9053c23..04d240f6 100644
--- a/lib/tasks/gitlab/backup.rake
+++ b/lib/tasks/gitlab/backup.rake
@@ -144,8 +144,7 @@ namespace :gitlab do
if Kernel.system("cd #{File.dirname(project.second)} > /dev/null 2>&1 && git clone --bare #{backup_path_repo}/#{project.first}.bundle #{project.first}.git > /dev/null 2>&1")
permission_commands = [
"sudo chmod -R g+rwX #{Gitlab.config.git_base_path}",
- "sudo chown -R #{Gitlab.config.ssh_user}:#{Gitlab.config.ssh_user} #{Gitlab.config.git_base_path}",
- "sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive"
+ "sudo chown -R #{Gitlab.config.ssh_user}:#{Gitlab.config.ssh_user} #{Gitlab.config.git_base_path}"
]
permission_commands.each { |command| Kernel.system(command) }
puts "[DONE]".green
diff --git a/lib/tasks/gitlab/enable_automerge.rake b/lib/tasks/gitlab/enable_automerge.rake
index 07f80586..0a1a0fa7 100644
--- a/lib/tasks/gitlab/enable_automerge.rake
+++ b/lib/tasks/gitlab/enable_automerge.rake
@@ -2,9 +2,7 @@ namespace :gitlab do
namespace :app do
desc "GITLAB | Enable auto merge"
task :enable_automerge => :environment do
- Gitlab::GitHost.system.new.configure do |git|
- git.admin_all_repo
- end
+ Gitlab::Gitolite.new.enable_automerge
Project.find_each do |project|
if project.repo_exists? && !project.satellite.exists?
diff --git a/lib/tasks/gitlab/gitolite_rebuild.rake b/lib/tasks/gitlab/gitolite_rebuild.rake
index 5ab17606..534aa315 100644
--- a/lib/tasks/gitlab/gitolite_rebuild.rake
+++ b/lib/tasks/gitlab/gitolite_rebuild.rake
@@ -16,7 +16,7 @@ namespace :gitlab do
task :update_keys => :environment do
puts "Starting Key"
Key.find_each(:batch_size => 100) do |key|
- key.update_repository
+ Gitlab::Gitolite.new.set_key(key.identifier, key.key, key.projects)
print '.'
end
puts "Done with keys"
diff --git a/lib/tasks/gitlab/status.rake b/lib/tasks/gitlab/status.rake
index 02d27d4b..e5b5e122 100644
--- a/lib/tasks/gitlab/status.rake
+++ b/lib/tasks/gitlab/status.rake
@@ -56,7 +56,7 @@ namespace :gitlab do
return
end
- gitolite_hooks_path = File.join("/home", Gitlab.config.ssh_user, "share", "gitolite", "hooks", "common")
+ gitolite_hooks_path = File.join(Gitlab.config.git_hooks_path, "common")
gitlab_hook_files = ['post-receive']
gitlab_hook_files.each do |file_name|
dest = File.join(gitolite_hooks_path, file_name)
@@ -81,7 +81,7 @@ namespace :gitlab do
next
end
- puts "post-reveice file ok".green
+ puts "post-receive file ok".green
end
end
diff --git a/lib/tasks/gitlab/test.rake b/lib/tasks/gitlab/test.rake
index 77e148cf..ad1bfb2e 100644
--- a/lib/tasks/gitlab/test.rake
+++ b/lib/tasks/gitlab/test.rake
@@ -1,5 +1,4 @@
namespace :gitlab do
- desc "GITLAB | Run both cucumber & rspec"
- task :test => ['cucumber', 'spec']
+ desc "GITLAB | Run both spinach and rspec"
+ task :test => ['spinach', 'spec']
end
-
diff --git a/lib/tasks/gitlab/write_hook.rake b/lib/tasks/gitlab/write_hook.rake
index 098331b8..5e9fc8eb 100644
--- a/lib/tasks/gitlab/write_hook.rake
+++ b/lib/tasks/gitlab/write_hook.rake
@@ -1,8 +1,8 @@
namespace :gitlab do
namespace :gitolite do
- desc "GITLAB | Write GITLAB hook for gitolite"
+ desc "GITLAB | Write GitLab hook for gitolite"
task :write_hooks => :environment do
- gitolite_hooks_path = File.join("/home", Gitlab.config.ssh_user, "share", "gitolite", "hooks", "common")
+ gitolite_hooks_path = File.join(Gitlab.config.git_hooks_path, "common")
gitlab_hooks_path = Rails.root.join("lib", "hooks")
gitlab_hook_files = ['post-receive']
diff --git a/lib/tasks/travis.rake b/lib/tasks/travis.rake
index 58767e10..13e32135 100644
--- a/lib/tasks/travis.rake
+++ b/lib/tasks/travis.rake
@@ -1,5 +1,5 @@
task :travis do
- ["cucumber", "rspec spec"].each do |cmd|
+ ["spinach", "rspec spec"].each do |cmd|
puts "Starting to run #{cmd}..."
system("export DISPLAY=:99.0 && bundle exec #{cmd}")
raise "#{cmd} failed!" unless $?.exitstatus == 0
diff --git a/resque_dev.sh b/resque_dev.sh
index b09cfd9e..0f1d6edb 100755
--- a/resque_dev.sh
+++ b/resque_dev.sh
@@ -1 +1,2 @@
-bundle exec rake environment resque:work QUEUE=post_receive,mailer,system_hook VVERBOSE=1
+mkdir -p tmp/pids
+bundle exec rake environment resque:work QUEUE=post_receive,mailer,system_hook VVERBOSE=1 PIDFILE=tmp/pids/resque_worker.pid RAILS_ENV=development BACKGROUND=yes
diff --git a/script/cucumber b/script/cucumber
deleted file mode 100755
index 7fa5c920..00000000
--- a/script/cucumber
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/env ruby
-
-vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
-if vendored_cucumber_bin
- load File.expand_path(vendored_cucumber_bin)
-else
- require 'rubygems' unless ENV['NO_RUBYGEMS']
- require 'cucumber'
- load Cucumber::BINARY
-end
diff --git a/spec/api/projects_spec.rb b/spec/api/projects_spec.rb
deleted file mode 100644
index ff45619e..00000000
--- a/spec/api/projects_spec.rb
+++ /dev/null
@@ -1,136 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::API do
- let(:user) { Factory :user }
- let!(:project) { Factory :project, owner: user }
- let!(:snippet) { Factory :snippet, author: user, project: project, title: 'example' }
- before { project.add_access(user, :read) }
-
- describe "GET /projects" do
- it "should return authentication error" do
- get "#{api_prefix}/projects"
- response.status.should == 401
- end
-
- describe "authenticated GET /projects" do
- it "should return an array of projects" do
- get "#{api_prefix}/projects?private_token=#{user.private_token}"
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['name'].should == project.name
- json_response.first['owner']['email'].should == user.email
- end
- end
- end
-
- describe "GET /projects/:id" do
- it "should return a project by id" do
- get "#{api_prefix}/projects/#{project.id}?private_token=#{user.private_token}"
- response.status.should == 200
- json_response['name'].should == project.name
- json_response['owner']['email'].should == user.email
- end
-
- it "should return a project by code name" do
- get "#{api_prefix}/projects/#{project.code}?private_token=#{user.private_token}"
- response.status.should == 200
- json_response['name'].should == project.name
- end
-
- it "should return a 404 error if not found" do
- get "#{api_prefix}/projects/42?private_token=#{user.private_token}"
- response.status.should == 404
- json_response['message'].should == '404 Not found'
- end
- end
-
- describe "GET /projects/:id/repository/branches" do
- it "should return an array of project branches" do
- get "#{api_prefix}/projects/#{project.code}/repository/branches?private_token=#{user.private_token}"
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['name'].should == project.repo.heads.sort_by(&:name).first.name
- end
- end
-
- describe "GET /projects/:id/repository/branches/:branch" do
- it "should return the branch information for a single branch" do
- get "#{api_prefix}/projects/#{project.code}/repository/branches/new_design?private_token=#{user.private_token}"
- response.status.should == 200
-
- json_response['name'].should == 'new_design'
- json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1'
- end
- end
-
- describe "GET /projects/:id/repository/tags" do
- it "should return an array of project tags" do
- get "#{api_prefix}/projects/#{project.code}/repository/tags?private_token=#{user.private_token}"
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['name'].should == project.repo.tags.sort_by(&:name).reverse.first.name
- end
- end
-
- describe "GET /projects/:id/snippets/:snippet_id" do
- it "should return a project snippet" do
- get "#{api_prefix}/projects/#{project.code}/snippets/#{snippet.id}?private_token=#{user.private_token}"
- response.status.should == 200
- json_response['title'].should == snippet.title
- end
- end
-
- describe "POST /projects/:id/snippets" do
- it "should create a new project snippet" do
- post "#{api_prefix}/projects/#{project.code}/snippets?private_token=#{user.private_token}",
- title: 'api test', file_name: 'sample.rb', code: 'test'
- response.status.should == 201
- json_response['title'].should == 'api test'
- end
- end
-
- describe "PUT /projects/:id/snippets" do
- it "should update an existing project snippet" do
- put "#{api_prefix}/projects/#{project.code}/snippets/#{snippet.id}?private_token=#{user.private_token}",
- code: 'updated code'
- response.status.should == 200
- json_response['title'].should == 'example'
- snippet.reload.content.should == 'updated code'
- end
- end
-
- describe "DELETE /projects/:id/snippets/:snippet_id" do
- it "should delete existing project snippet" do
- expect {
- delete "#{api_prefix}/projects/#{project.code}/snippets/#{snippet.id}?private_token=#{user.private_token}"
- }.to change { Snippet.count }.by(-1)
- end
- end
-
- describe "GET /projects/:id/snippets/:snippet_id/raw" do
- it "should get a raw project snippet" do
- get "#{api_prefix}/projects/#{project.code}/snippets/#{snippet.id}/raw?private_token=#{user.private_token}"
- response.status.should == 200
- end
- end
-
- describe "GET /projects/:id/:sha/blob" do
- it "should get the raw file contents" do
- get "#{api_prefix}/projects/#{project.code}/repository/commits/master/blob?filepath=README.md&private_token=#{user.private_token}"
-
- response.status.should == 200
- end
-
- it "should return 404 for invalid branch_name" do
- get "#{api_prefix}/projects/#{project.code}/repository/commits/invalid_branch_name/blob?filepath=README.md&private_token=#{user.private_token}"
-
- response.status.should == 404
- end
-
- it "should return 404 for invalid file" do
- get "#{api_prefix}/projects/#{project.code}/repository/commits/master/blob?filepath=README.invalid&private_token=#{user.private_token}"
-
- response.status.should == 404
- end
- end
-end
diff --git a/spec/api/users_spec.rb b/spec/api/users_spec.rb
deleted file mode 100644
index 32b9379d..00000000
--- a/spec/api/users_spec.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::API do
- let(:user) { Factory :user }
-
- describe "GET /users" do
- it "should return authentication error" do
- get "#{api_prefix}/users"
- response.status.should == 401
- end
-
- describe "authenticated GET /users" do
- it "should return an array of users" do
- get "#{api_prefix}/users?private_token=#{user.private_token}"
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['email'].should == user.email
- end
- end
- end
-
- describe "GET /users/:id" do
- it "should return a user by id" do
- get "#{api_prefix}/users/#{user.id}?private_token=#{user.private_token}"
- response.status.should == 200
- json_response['email'].should == user.email
- end
- end
-
- describe "GET /user" do
- it "should return current user" do
- get "#{api_prefix}/user?private_token=#{user.private_token}"
- response.status.should == 200
- json_response['email'].should == user.email
- end
- end
-end
diff --git a/spec/factories.rb b/spec/factories.rb
index ab2ca468..92790a3f 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -1,92 +1,133 @@
-require File.join(Rails.root, 'spec', 'factory')
-
-Factory.add(:project, Project) do |obj|
- obj.name = Faker::Internet.user_name
- obj.path = 'gitlabhq'
- obj.owner = Factory(:user)
- obj.code = 'LGT'
+# Backwards compatibility with the old method
+def Factory(type, *args)
+ FactoryGirl.create(type, *args)
end
-Factory.add(:project_without_owner, Project) do |obj|
- obj.name = Faker::Internet.user_name
- obj.path = 'gitlabhq'
- obj.code = 'LGT'
+module Factory
+ def self.create(type, *args)
+ FactoryGirl.create(type, *args)
+ end
+
+ def self.new(type, *args)
+ FactoryGirl.build(type, *args)
+ end
+ def self.attributes(type, *args)
+ FactoryGirl.attributes_for(type, *args)
+ end
end
-Factory.add(:public_project, Project) do |obj|
- obj.name = Faker::Internet.user_name
- obj.path = 'gitlabhq'
- obj.private_flag = false
- obj.owner = Factory(:user)
- obj.code = 'LGT'
-end
+FactoryGirl.define do
+ sequence :sentence, aliases: [:title, :content] do
+ Faker::Lorem.sentence
+ end
-Factory.add(:user, User) do |obj|
- obj.email = Faker::Internet.email
- obj.password = "123456"
- obj.name = Faker::Name.name
- obj.password_confirmation = "123456"
-end
+ sequence :name, aliases: [:file_name] do
+ Faker::Name.name
+ end
-Factory.add(:admin, User) do |obj|
- obj.email = Faker::Internet.email
- obj.password = "123456"
- obj.name = Faker::Name.name
- obj.password_confirmation = "123456"
- obj.admin = true
-end
+ sequence(:url) { Faker::Internet.uri('http') }
-Factory.add(:issue, Issue) do |obj|
- obj.title = Faker::Lorem.sentence
- obj.author = Factory :user
- obj.assignee = Factory :user
-end
+ factory :user, aliases: [:author, :assignee, :owner] do
+ email { Faker::Internet.email }
+ name
+ password "123456"
+ password_confirmation { password }
-Factory.add(:merge_request, MergeRequest) do |obj|
- obj.title = Faker::Lorem.sentence
- obj.author = Factory :user
- obj.assignee = Factory :user
- obj.source_branch = "master"
- obj.target_branch = "stable"
- obj.closed = false
-end
+ trait :admin do
+ admin true
+ end
-Factory.add(:snippet, Snippet) do |obj|
- obj.title = Faker::Lorem.sentence
- obj.file_name = Faker::Lorem.sentence
- obj.content = Faker::Lorem.sentences
-end
+ factory :admin, traits: [:admin]
+ end
-Factory.add(:note, Note) do |obj|
- obj.note = Faker::Lorem.sentence
-end
+ factory :project do
+ sequence(:name) { |n| "project#{n}" }
+ path { name }
+ code { name }
+ owner
+ end
-Factory.add(:key, Key) do |obj|
- obj.title = "Example key"
- obj.key = File.read(File.join(Rails.root, "db", "pkey.example"))
-end
+ factory :users_project do
+ user
+ project
+ end
-Factory.add(:project_hook, ProjectHook) do |obj|
- obj.url = Faker::Internet.uri("http")
-end
+ factory :issue do
+ title
+ author
+ project
-Factory.add(:system_hook, SystemHook) do |obj|
- obj.url = Faker::Internet.uri("http")
-end
+ trait :closed do
+ closed true
+ end
-Factory.add(:wiki, Wiki) do |obj|
- obj.title = Faker::Lorem.sentence
- obj.content = Faker::Lorem.sentence
- obj.user = Factory(:user)
- obj.project = Factory(:project)
-end
+ factory :closed_issue, traits: [:closed]
+ end
-Factory.add(:event, Event) do |obj|
- obj.title = Faker::Lorem.sentence
- obj.project = Factory(:project)
-end
+ factory :merge_request do
+ title
+ author
+ project
+ source_branch "master"
+ target_branch "stable"
+ end
-Factory.add(:milestone, Milestone) do |obj|
- obj.title = Faker::Lorem.sentence
- obj.due_date = Date.today + 1.month
+ factory :note do
+ project
+ note "Note"
+ end
+
+ factory :event do
+ end
+
+ factory :key do
+ title
+ key do
+ """
+ ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4
+ 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4
+ soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=
+ """
+ end
+
+ factory :deploy_key do
+ project
+ end
+
+ factory :personal_key do
+ user
+ end
+ end
+
+ factory :milestone do
+ title
+ project
+ end
+
+ factory :system_hook do
+ url
+ end
+
+ factory :project_hook do
+ url
+ end
+
+ factory :wiki do
+ title
+ content
+ user
+ end
+
+ factory :snippet do
+ project
+ author
+ title
+ content
+ file_name
+ end
+
+ factory :protected_branch do
+ name
+ project
+ end
end
diff --git a/spec/factories_spec.rb b/spec/factories_spec.rb
new file mode 100644
index 00000000..5ccc17bd
--- /dev/null
+++ b/spec/factories_spec.rb
@@ -0,0 +1,9 @@
+require 'spec_helper'
+
+FactoryGirl.factories.map(&:name).each do |factory_name|
+ describe "#{factory_name} factory" do
+ it 'should be valid' do
+ build(factory_name).should be_valid
+ end
+ end
+end
diff --git a/spec/factory.rb b/spec/factory.rb
deleted file mode 100644
index 1758b4d6..00000000
--- a/spec/factory.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-class Factory
- @factories = {}
-
- class << self
- def add(name, klass, &block)
- @factories[name] = [klass, block]
- end
-
- def create(name, opts = {})
- new(name, opts).tap(&:save!)
- end
-
- def new(name, opts = {})
- factory= @factories[name]
- factory[0].new.tap do |obj|
- factory[1].call(obj)
- end.tap do |obj|
- opts.each do |k, opt|
- obj.send("#{k}=", opt)
- end
- end
- end
- end
-end
-
-def Factory(name, opts={})
- Factory.create name, opts
-end
-
diff --git a/spec/helpers/gitlab_flavored_markdown_spec.rb b/spec/helpers/gitlab_flavored_markdown_spec.rb
deleted file mode 100644
index e147cb39..00000000
--- a/spec/helpers/gitlab_flavored_markdown_spec.rb
+++ /dev/null
@@ -1,232 +0,0 @@
-require "spec_helper"
-
-describe GitlabMarkdownHelper do
- before do
- @project = Project.find_by_path("gitlabhq") || Factory(:project)
- @commit = @project.repo.commits.first.parents.first
- @commit = CommitDecorator.decorate(Commit.new(@commit))
- @other_project = Factory :project, path: "OtherPath", code: "OtherCode"
- @fake_user = Factory :user, name: "fred"
- end
-
- describe "#gfm" do
- it "should return text if @project is not set" do
- @project = nil
-
- gfm("foo").should == "foo"
- end
-
- describe "referencing a commit" do
- it "should link using a full id" do
- gfm("Reverts changes from #{@commit.id}").should == "Reverts changes from #{link_to @commit.id, project_commit_path(@project, id: @commit.id), title: "Commit: #{@commit.author_name} - #{@commit.title}", class: "gfm gfm-commit "}"
- end
-
- it "should link using a short id" do
- gfm("Backported from #{@commit.id[0, 6]}").should == "Backported from #{link_to @commit.id[0, 6], project_commit_path(@project, id: @commit.id), title: "Commit: #{@commit.author_name} - #{@commit.title}", class: "gfm gfm-commit "}"
- end
-
- it "should link with adjecent text" do
- gfm("Reverted (see #{@commit.id})").should == "Reverted (see #{link_to @commit.id, project_commit_path(@project, id: @commit.id), title: "Commit: #{@commit.author_name} - #{@commit.title}", class: "gfm gfm-commit "})"
- end
-
- it "should not link with an invalid id" do
- gfm("What happened in 12345678?").should == "What happened in 12345678?"
- end
- end
-
- describe "referencing a team member" do
- it "should link using a simple name" do
- user = Factory :user, name: "barry"
- @project.users << user
- member = @project.users_projects.where(user_id: user).first
-
- gfm("@#{user.name} you are right").should == "#{link_to "@#{user.name}", project_team_member_path(@project, member), class: "gfm gfm-team_member "} you are right"
- end
-
- it "should link using a name with dots" do
- user = Factory :user, name: "alphA.Beta"
- @project.users << user
- member = @project.users_projects.where(user_id: user).first
-
- gfm("@#{user.name} you are right").should == "#{link_to "@#{user.name}", project_team_member_path(@project, member), class: "gfm gfm-team_member "} you are right"
- end
-
- it "should link using name with underscores" do
- user = Factory :user, name: "ping_pong_king"
- @project.users << user
- member = @project.users_projects.where(user_id: user).first
-
- gfm("@#{user.name} you are right").should == "#{link_to "@#{user.name}", project_team_member_path(@project, member), class: "gfm gfm-team_member "} you are right"
- end
-
- it "should link with adjecent text" do
- user = Factory.create(:user, name: "ace")
- @project.users << user
- member = @project.users_projects.where(user_id: user).first
-
- gfm("Mail the Admin (@#{user.name})").should == "Mail the Admin (#{link_to "@#{user.name}", project_team_member_path(@project, member), class: "gfm gfm-team_member "})"
- end
-
- it "should add styles" do
- user = Factory :user, name: "barry"
- @project.users << user
- gfm("@#{user.name} you are right").should have_selector(".gfm.gfm-team_member")
- end
-
- it "should not link using a bogus name" do
- gfm("What hapened to @foo?").should == "What hapened to @foo?"
- end
- end
-
- describe "referencing an issue" do
- before do
- @issue = Factory :issue, assignee: @fake_user, author: @fake_user, project: @project
- @invalid_issue = Factory :issue, assignee: @fake_user, author: @fake_user, project: @other_project
- end
-
- it "should link using a correct id" do
- gfm("Fixes ##{@issue.id}").should == "Fixes #{link_to "##{@issue.id}", project_issue_path(@project, @issue), title: "Issue: #{@issue.title}", class: "gfm gfm-issue "}"
- end
-
- it "should link with adjecent text" do
- gfm("This has already been discussed (see ##{@issue.id})").should == "This has already been discussed (see #{link_to "##{@issue.id}", project_issue_path(@project, @issue), title: "Issue: #{@issue.title}", class: "gfm gfm-issue "})"
- end
-
- it "should add styles" do
- gfm("Fixes ##{@issue.id}").should have_selector(".gfm.gfm-issue")
- end
-
- it "should not link using an invalid id" do
- gfm("##{@invalid_issue.id} has been marked duplicate of this").should == "##{@invalid_issue.id} has been marked duplicate of this"
- end
- end
-
- describe "referencing a merge request" do
- before do
- @merge_request = Factory :merge_request, assignee: @fake_user, author: @fake_user, project: @project
- @invalid_merge_request = Factory :merge_request, assignee: @fake_user, author: @fake_user, project: @other_project
- end
-
- it "should link using a correct id" do
- gfm("Fixed in !#{@merge_request.id}").should == "Fixed in #{link_to "!#{@merge_request.id}", project_merge_request_path(@project, @merge_request), title: "Merge Request: #{@merge_request.title}", class: "gfm gfm-merge_request "}"
- end
-
- it "should link with adjecent text" do
- gfm("This has been fixed already (see !#{@merge_request.id})").should == "This has been fixed already (see #{link_to "!#{@merge_request.id}", project_merge_request_path(@project, @merge_request), title: "Merge Request: #{@merge_request.title}", class: "gfm gfm-merge_request "})"
- end
-
- it "should add styles" do
- gfm("Fixed in !#{@merge_request.id}").should have_selector(".gfm.gfm-merge_request")
- end
-
- it "should not link using an invalid id" do
- gfm("!#{@invalid_merge_request.id} violates our coding guidelines")
- end
- end
-
- describe "referencing a snippet" do
- before do
- @snippet = Factory.create(:snippet,
- title: "Render asset to string",
- author: @fake_user,
- project: @project)
- end
-
- it "should link using a correct id" do
- gfm("Check out $#{@snippet.id}").should == "Check out #{link_to "$#{@snippet.id}", project_snippet_path(@project, @snippet), title: "Snippet: #{@snippet.title}", class: "gfm gfm-snippet "}"
- end
-
- it "should link with adjecent text" do
- gfm("I have created a snippet for that ($#{@snippet.id})").should == "I have created a snippet for that (#{link_to "$#{@snippet.id}", project_snippet_path(@project, @snippet), title: "Snippet: #{@snippet.title}", class: "gfm gfm-snippet "})"
- end
-
- it "should add styles" do
- gfm("Check out $#{@snippet.id}").should have_selector(".gfm.gfm-snippet")
- end
-
- it "should not link using an invalid id" do
- gfm("Don't use $1234").should == "Don't use $1234"
- end
- end
-
- it "should link to multiple things" do
- user = Factory :user, name: "barry"
- @project.users << user
- member = @project.users_projects.where(user_id: user).first
-
- gfm("Let @#{user.name} fix the *mess* in #{@commit.id}").should == "Let #{link_to "@#{user.name}", project_team_member_path(@project, member), class: "gfm gfm-team_member "} fix the *mess* in #{link_to @commit.id, project_commit_path(@project, id: @commit.id), title: "Commit: #{@commit.author_name} - #{@commit.title}", class: "gfm gfm-commit "}"
- end
-
- it "should not trip over other stuff", focus: true do
- gfm("_Please_ *stop* 'helping' and all the other b*$#%' you do.").should == "_Please_ *stop* 'helping' and all the other b*$#%' you do."
- end
-
- it "should not touch HTML entities" do
- gfm("We'll accept good pull requests.").should == "We'll accept good pull requests."
- end
-
- it "should forward HTML options to links" do
- gfm("fixed in #{@commit.id}", class: "foo").should have_selector("a.foo")
- end
- end
-
- describe "#link_to_gfm" do
- let(:issue1) { Factory :issue, assignee: @fake_user, author: @fake_user, project: @project }
- let(:issue2) { Factory :issue, assignee: @fake_user, author: @fake_user, project: @project }
-
- it "should handle references nested in links with all the text" do
- link_to_gfm("This should finally fix ##{issue1.id} and ##{issue2.id} for real", project_commit_path(@project, id: @commit.id)).should == "#{link_to "This should finally fix ", project_commit_path(@project, id: @commit.id)}#{link_to "##{issue1.id}", project_issue_path(@project, issue1), title: "Issue: #{issue1.title}", class: "gfm gfm-issue "}#{link_to " and ", project_commit_path(@project, id: @commit.id)}#{link_to "##{issue2.id}", project_issue_path(@project, issue2), title: "Issue: #{issue2.title}", class: "gfm gfm-issue "}#{link_to " for real", project_commit_path(@project, id: @commit.id)}"
- end
-
- it "should forward HTML options" do
- link_to_gfm("This should finally fix ##{issue1.id} for real", project_commit_path(@project, id: @commit.id), class: "foo").should have_selector(".foo")
- end
- end
-
- describe "#markdown" do
- before do
- @issue = Factory :issue, assignee: @fake_user, author: @fake_user, project: @project
- @merge_request = Factory :merge_request, assignee: @fake_user, author: @fake_user, project: @project
- @note = Factory.create(:note,
- note: "Screenshot of the new feature",
- project: @project,
- noteable_id: @commit.id,
- noteable_type: "Commit",
- attachment: "screenshot123.jpg")
- @snippet = Factory.create(:snippet,
- title: "Render asset to string",
- author: @fake_user,
- project: @project)
-
- @other_user = Factory :user, name: "bill"
- @project.users << @other_user
- @member = @project.users_projects.where(user_id: @other_user).first
- end
-
- it "should handle references in paragraphs" do
- markdown("\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. #{@commit.id} Nam pulvinar sapien eget odio adipiscing at faucibus orci vestibulum.\n").should == "Lorem ipsum dolor sit amet, consectetur adipiscing elit. #{link_to @commit.id, project_commit_path(@project, id: @commit.id), title: "Commit: #{@commit.author_name} - #{@commit.title}", class: "gfm gfm-commit "} Nam pulvinar sapien eget odio adipiscing at faucibus orci vestibulum.
\n" - end - - it "should handle references in headers" do - markdown("\n# Working around ##{@issue.id} for now\n## Apply !#{@merge_request.id}").should == "Apply #{link_to "!#{@merge_request.id}", project_merge_request_path(@project, @merge_request), title: "Merge Request: #{@merge_request.title}", class: "gfm gfm-merge_request "} ASAP
\n" - end - - it "should leave code blocks untouched" do - markdown("\n some code from $#{@snippet.id}\n here too\n").should == "some code from $#{@snippet.id}\nhere too\n
\nsome code from $#{@snippet.id}\nhere too\n
\nDon't use $#{@snippet.id}
here.
some code from $#{snippet.id}\nhere too\n
\nsome code from $#{snippet.id}\nhere too\n
\nDon't use $#{snippet.id}
here.