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:")
+ # => "
+ module Markdown
REFERENCE_PATTERN = %r{
- ([^\w&;])? # Prefix (1)
+ (\W)? # Prefix (1)
( # Reference (2)
@([\w\._]+) # User name (3)
|[#!$](\d+) # Issue/MR/Snippet ID (4)
|([\h]{6,40}) # Commit ID (5)
)
- ([^\w&;])? # Suffix (6)
+ (\W)? # Suffix (6)
}x.freeze
+ EMOJI_PATTERN = %r{(:(\S+):)}.freeze
+
attr_reader :html_options
- def initialize(project, html_options = {})
- @project = project
+ # Public: Parse the provided text with GitLab-Flavored Markdown
+ #
+ # 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
+ def gfm(text, html_options = {})
+ return text if text.nil?
+
+ # Duplicate the string so we don't alter the original, then call to_str
+ # to cast it back to a String instead of a SafeBuffer. This is required
+ # for gsub calls to work as we need them to.
+ text = text.dup.to_str
+
@html_options = html_options
+
+ # 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
+
+ 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.