From a64aff2f1c1ddc77b00211489d74fbc23c0c2fa2 Mon Sep 17 00:00:00 2001 From: Florian Unglaub Date: Fri, 3 Aug 2012 17:27:39 +0200 Subject: [PATCH 001/123] Omniauth Support --- Gemfile | 4 ++ Gemfile.lock | 32 ++++++++++++++ app/assets/stylesheets/auth_methods.scss | 10 +++++ app/assets/stylesheets/main.scss | 26 ++++++------ .../omniauth_callbacks_controller.rb | 32 +++++++++++++- app/helpers/application_helper.rb | 11 +++-- app/views/devise/sessions/new.html.erb | 13 ++++-- app/views/layouts/profile.html.haml | 2 +- app/views/profile/password.html.haml | 40 ++++++++++++------ app/views/profile/show.html.haml | 7 +++ config/gitlab.yml.example | 22 +++++++--- config/initializers/1_settings.rb | 19 ++++++--- ...803152018_add_provider_and_uid_to_users.rb | 6 +++ db/schema.rb | 32 +++++++------- .../assets/images/authbuttons/github_32.png | Bin 0 -> 1931 bytes .../assets/images/authbuttons/github_64.png | Bin 0 -> 4447 bytes .../assets/images/authbuttons/google_32.png | Bin 0 -> 1615 bytes .../assets/images/authbuttons/google_64.png | Bin 0 -> 3446 bytes .../assets/images/authbuttons/twitter_32.png | Bin 0 -> 1439 bytes .../assets/images/authbuttons/twitter_64.png | Bin 0 -> 3384 bytes 20 files changed, 195 insertions(+), 61 deletions(-) create mode 100644 app/assets/stylesheets/auth_methods.scss create mode 100644 db/migrate/20120803152018_add_provider_and_uid_to_users.rb create mode 100644 vendor/assets/images/authbuttons/github_32.png create mode 100644 vendor/assets/images/authbuttons/github_64.png create mode 100644 vendor/assets/images/authbuttons/google_32.png create mode 100644 vendor/assets/images/authbuttons/google_64.png create mode 100644 vendor/assets/images/authbuttons/twitter_32.png create mode 100644 vendor/assets/images/authbuttons/twitter_64.png diff --git a/Gemfile b/Gemfile index d2a5728f..12610b65 100644 --- a/Gemfile +++ b/Gemfile @@ -8,6 +8,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" diff --git a/Gemfile.lock b/Gemfile.lock index 7356c35e..b34f401b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -166,6 +166,8 @@ GEM eventmachine (0.12.10) execjs (1.4.0) multi_json (~> 1.0) + faraday (0.8.1) + multipart-post (~> 1.1) ffaker (1.14.0) ffi (1.0.11) foreman (0.47.0) @@ -191,6 +193,7 @@ GEM httparty (0.8.3) multi_json (~> 1.0) multi_xml + httpauth (0.1) i18n (0.6.0) journey (1.0.4) jquery-rails (2.0.2) @@ -200,6 +203,8 @@ GEM jquery-rails railties (>= 3.1.0) json (1.7.4) + jwt (0.1.5) + multi_json (>= 1.0) kaminari (0.13.0) actionpack (>= 3.0.0) activesupport (>= 3.0.0) @@ -223,12 +228,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.6) + 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.1) + omniauth (~> 1.0) + omniauth-oauth2 (~> 1.0) + 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.12) + multi_json (~> 1.3) + omniauth-oauth (~> 1.0) orm_adapter (0.3.0) polyglot (0.3.3) posix-spawn (0.3.6) @@ -411,7 +439,11 @@ DEPENDENCIES minitest (>= 2.10) modernizr (= 2.5.3) mysql2 + omniauth + omniauth-github + omniauth-google-oauth2 omniauth-ldap! + omniauth-twitter pry pygments.rb! rack-mini-profiler diff --git a/app/assets/stylesheets/auth_methods.scss b/app/assets/stylesheets/auth_methods.scss new file mode 100644 index 00000000..ed6f5b0f --- /dev/null +++ b/app/assets/stylesheets/auth_methods.scss @@ -0,0 +1,10 @@ +.auth_methods { + &ul { + margin: 0; + text-align:center; + padding: 5px; + &li { + display: inline; + } + } +} diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss index 5613f1e8..0e3de4e8 100644 --- a/app/assets/stylesheets/main.scss +++ b/app/assets/stylesheets/main.scss @@ -3,8 +3,8 @@ /** GITLAB colors **/ $text_color:#222; -$lite_text_color: #666; -$link_color:#2A79A3; +$lite_text_color: #666; +$link_color:#2A79A3; $active_link_color:#2FA0BB; $active_bg_color:#79C3E0; $active_bd_color: #2FA0BB; @@ -31,7 +31,7 @@ $hover: #FDF5D9; box-shadow: 0 0 3px #ddd; } -@mixin solid_shade { +@mixin solid_shade { -moz-box-shadow: 0 0 0 3px #eee; -webkit-box-shadow: 0 0 0 3px #eee; box-shadow: 0 0 0 3px #eee; @@ -73,21 +73,21 @@ $hover: #FDF5D9; /** - * Header of application. + * Header of application. * Contain application logo, search panel, profile icon */ @import "sections/header.scss"; /** - * Navigation menu of application. + * Navigation menu of application. * Panel with links to pages depends on project, profile or admin area */ @import "sections/nav.scss"; /** - * This file represent some UI that can be changed - * during web app restyle or theme select. - * + * This file represent some UI that can be changed + * during web app restyle or theme select. + * * Next items should be placed there * - link, button colors * - header restyles @@ -118,11 +118,11 @@ $hover: #FDF5D9; * Most of application styles placed here. * This file represent common UI that should not be changed between themes * or project restyling like form width or user avatar class or commit title - * + * * TODO: clean it */ @import "common.scss"; - +@import "auth_methods.scss"; /** * Styles related to specific part of app @@ -140,17 +140,17 @@ $hover: #FDF5D9; @import "ref_select.scss"; /** - * Code (files list) styles. Browsing project files there + * Code (files list) styles. Browsing project files there */ @import "sections/tree.scss"; /** - * This file represent notes(comments) styles + * This file represent notes(comments) styles */ @import "sections/notes.scss"; /** - * Devise styles + * Devise styles */ @import "sections/login.scss"; diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index d19931e9..84e578a3 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -9,7 +9,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. info = request.env["omniauth.auth"]["info"] @@ -20,4 +20,34 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController sign_in_and_redirect @user end + Settings.omniauth_providers.each do |provider| + define_method provider['name'] do + handle_omniauth + end + 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.uid = uid + current_user.provider = provider + current_user.save + redirect_to profile_path + else + @user = User.find_by_provider_and_uid(provider, uid) + + 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/helpers/application_helper.rb b/app/helpers/application_helper.rb index 51569b06..8a457cea 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -75,16 +75,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" @@ -123,4 +123,9 @@ module ApplicationHelper def hexdigest(string) Digest::SHA1.hexdigest string end + + def authbutton(provider, size = 64) + image_tag("authbuttons/#{provider.to_s.split('_').first}_#{size}.png", + alt: "Sign in with #{provider.to_s.titleize}" ) + end end diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index a0383866..6b334b87 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -14,10 +14,15 @@
<%= render :partial => "devise/shared/links" %>
<%- if devise_mapping.omniauthable? %> - <%- resource_class.omniauth_providers.each do |provider| %> -
- <%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider), :class => "btn primary" %>
- <% end -%> +
+
+ +
<% end -%> <% end %> diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml index b624415d..810b346f 100644 --- a/app/views/layouts/profile.html.haml +++ b/app/views/layouts/profile.html.haml @@ -10,7 +10,7 @@ = link_to "Profile", profile_path %li{class: tab_class(:password)} - = link_to "Password", profile_password_path + = link_to "Authentication", profile_password_path %li{class: tab_class(:ssh_keys)} = link_to keys_path do diff --git a/app/views/profile/password.html.haml b/app/views/profile/password.html.haml index 257dacb1..1d4d468c 100644 --- a/app/views/profile/password.html.haml +++ b/app/views/profile/password.html.haml @@ -1,19 +1,31 @@ %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 += form_for @user, url: profile_password_path, method: :put do |f| + .row + .span7 + .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 + + - if Settings.omniauth.enabled + .span5.right + .auth_methods.alert.alert-info + %strong Tip: Use one of the following sites to login + %ul + - User.omniauth_providers.each do |provider| + %li= link_to authbutton(provider), | + omniauth_authorize_path(User, provider) | .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..4d89cd3d 100644 --- a/app/views/profile/show.html.haml +++ b/app/views/profile/show.html.haml @@ -49,6 +49,13 @@ %strong Tip: You can change your avatar at gravatar.com + - if Settings.omniauth.enabled && @user.provider? + %h4 + Omniauth Providers: + = link_to "Change", profile_password_path, class: "btn small right" + You can login through #{@user.provider.titleize}! + = authbutton(@user.provider, 32) + %h4 Personal projects: %small.right diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 1818f2c0..622ac9ec 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -1,4 +1,4 @@ -# # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # Gitlab application config file # # # # # # # # # # # # # # # # # # # @@ -19,14 +19,14 @@ email: # Application specific settings # Like default project limit for user etc -app: - default_projects_limit: 10 +app: + default_projects_limit: 10 # backup_path: "/vol/backups" # default: Rails.root + backups/ # backup_keep_time: 604800 # default: 0 (forever) (in seconds) -# -# 2. Advanced settings: +# +# 2. Advanced settings: # ========================== # Git Hosting configuration @@ -49,3 +49,15 @@ git: git_max_size: 5242880 # 5.megabytes # Git timeout to read commit, in seconds git_timeout: 10 + +# Omniauth configuration +# omniauth: +# enabled: true +# 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' } diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 5c5987a8..741a29d5 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 @@ -111,5 +111,14 @@ class Settings < Settingslogic def backup_keep_time app['backup_keep_time'] || 0 end + + def omniauth_enabled? + omniauth['enabled'] || false + end + + def omniauth_providers + omniauth['providers'] || [] + end + end end diff --git a/db/migrate/20120803152018_add_provider_and_uid_to_users.rb b/db/migrate/20120803152018_add_provider_and_uid_to_users.rb new file mode 100644 index 00000000..14f53e4e --- /dev/null +++ b/db/migrate/20120803152018_add_provider_and_uid_to_users.rb @@ -0,0 +1,6 @@ +class AddProviderAndUidToUsers < ActiveRecord::Migration + def change + add_column :users, :provider, :string + add_column :users, :uid, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index c4c54f56..5ac159d8 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 => 20120712080407) do +ActiveRecord::Schema.define(:version => 20120803152018) do create_table "events", :force => true do |t| t.string "target_type" @@ -146,31 +146,33 @@ ActiveRecord::Schema.define(:version => 20120712080407) do end create_table "users", :force => true do |t| - t.string "email", :default => "", :null => false - t.string "encrypted_password", :limit => 128, :default => "", :null => false + t.string "email", :default => "", :null => false + t.string "encrypted_password", :default => "", :null => false t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" - t.integer "sign_in_count", :default => 0 + t.integer "sign_in_count", :default => 0 t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" t.string "current_sign_in_ip" t.string "last_sign_in_ip" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false t.string "name" - t.boolean "admin", :default => false, :null => false - t.integer "projects_limit", :default => 10 - t.string "skype", :default => "", :null => false - t.string "linkedin", :default => "", :null => false - t.string "twitter", :default => "", :null => false + t.boolean "admin", :default => false, :null => false + t.integer "projects_limit", :default => 10 + t.string "skype", :default => "", :null => false + t.string "linkedin", :default => "", :null => false + t.string "twitter", :default => "", :null => false t.string "authentication_token" - t.boolean "dark_scheme", :default => false, :null => false - t.integer "theme_id", :default => 1, :null => false + t.boolean "dark_scheme", :default => false, :null => false + t.integer "theme_id", :default => 1, :null => false t.string "bio" - t.boolean "blocked", :default => false, :null => false - t.integer "failed_attempts", :default => 0 + t.boolean "blocked", :default => false, :null => false + t.integer "failed_attempts", :default => 0 t.datetime "locked_at" + t.string "provider" + t.string "uid" end add_index "users", ["email"], :name => "index_users_on_email", :unique => true diff --git a/vendor/assets/images/authbuttons/github_32.png b/vendor/assets/images/authbuttons/github_32.png new file mode 100644 index 0000000000000000000000000000000000000000..247e52a5f4282110243afa350cd4a13b0154c2a1 GIT binary patch literal 1931 zcmV;62Xy#}P)4Uz|7>$8ns*j_q@J-|yI` zcA9nF_=Ch}y*}r>-*?{c`QG~h{@;i68RtIB(C=xJN5B7^FA!>aTvZj<-uuGnY~Nze zz4UrF7LzNGWXTk#>pHTzTa+K4!aGHKGX%Ps)+gSOTD-;77-f=Vo92goTiCqP1m4ldj6iS#MkuO&)H0-_u}cd zA36Ew;}eBFEydb+_}h;?UFE9$j?-a>v%-!t)e6NT!|$#V3u@ez7@nR(S(z1nj|)C} z_Eb5Owf^ToAH78h;|;nrl7G@v1u(}YbaAEd)Yl z5OR?jHi#>EeW2(?5mR01z!$f*VEd*3hNosrmY)Cj5I*P|#M!GiO%SXJHc@dTNO=w1 zmRgFU!~~3RS6c|J4R!E1D@;B+6~CMzd-6RGJNW^Nj8jIALQ=HAW~RSpM~q355J!BolGG z_Lo=1{5x;Hf!$x(hd`(q6GH=-pN*1p=1OzKdH_`vdIhg$?+?{_VajXS31id6QS;s)Uy`!Tj`E7QcMqC^DJM ze-B`1QxNrDH}-739rG)xv;dV%rG)JZgPo80nQR8X{l)X2x73{xr9k+!(-H=X&tv&vzi` zuQqwhbn=r_gcwA@fujqHSXf#{jOfbXnAjj5i<$4V1Zr^NXWv5`=Y(}$e{*~q;ln@L z7(g$1@>F6K?PP-edv=-;!C9@+Zl_}86n1BaJMqC4vnp~GEVJ42xkSS0-yA_O)PkY$ zG%CCv_z@uo%H4wrbi>hxin5-Y64JrW&y_4|@OebYUbr!6mS2A$XhaKzW{~D}S1tN} z`~y^N3B&)`0U$a5$xdiA4w|slNBtuo>o_wrGjPf|q!Npmn~7p}dJ6G{80s2BSRh*` zSJRMI6Y%ZY4POU=PbKdy3fNp)zQMRUG%nQ7Be|Nw>7G9P{vYpRloC{-%9U9aBfHVP ztJ;TeKJk>eKlb;tKx_hg9{&cyyPJV*8tLU#%nVL^aul#Sxt_Pw*O;9U7aiW10j3Gm zrUs)lyGLiROl6k4A_g7`Z^Pkdeu(Fe9i?>{Jo&X0oYX_`NKws@70cZLunE`)*aUUe zt`e_yQ$IWja6qU*rd zzvc1z+8j)xL3H^Wa>-awc3;>CMmTvhe{|7XiOZI(&W>`j`IG-=b4Hng_2SV2@27Y;`RIeNt90HTQCaXHq* zaRG5(5RV@8xL33sgkmXJTLXlKwlr;;X5ZST*(aS$Cfm$>?|uLMZRXEpv&cF2wQv6R z-v96J_uYE~aHU;oSK5_!rTzalVUc5nMb7zOHQCUYjQ|>B!*0L-o8K=M6H}_3u7s*! zCDBT(?T12%>~t5Fo+nfKR{gI&eAcQ4>#f_Q7-YCxBp*@tz5DjX~(NM>|rYarTKv0b<-_5+i$q(SyzH< zx5I7&r^5jbyB&{qut^exaRmig8Bvq7(%jJ5Kg8DKu-VvnJI=S;c(?Oz!}~UgbsHkq zhDS-Vv2zLEPYAd1BVCJh6a_{A0nY_Iig=9&1%-Z6erl? zAb_4F?s(@-kK3J&DhFSz!(mevM2o?%ww)h@>e50;PH;uNU~6R={JXIQI6*Zkt6ZT{ zSD~T|p|J9tZZH83hn1sYURVw*^R;_&)O*9q3Egvh@{4|kuh@w_Xr&jVIMjFEao?A( zNz2ZCh^VJ`g##GXI3nhPA;|ZnMZF|FH5qyaN7$kzqNpgbql!RARTG5`UA-3daYTJl zrMRe4Uhklun-+T5vK)BH_qiXh45M6Pi%&KVfH1Y2>b;Al} z!^jotk?w~DnR5l|k1)Sa%L=m}d=8N8UU4H{JcE5UQWwNSfEWyg-6E%u&88rMopXu^ zoC4HZ`Yu``V0DfM&f>GlsTsyGyQ;5(l_^Q4G1;gus8Q>lqzGXY9f2W1B`zUBK==iMUSRT9K)5HE7NY~0Ofi;|1O~Xsm5->hqX7Y9 z6O%AaZs~9p~IM&3Fz$nXff((cQ2+{W$7YK~{iuMcB zf23MigOT)y!2g8^Lpty#TP()4fr5enl0#L_Bo4UJxl9VmvGv@5<$KBzsJE_PJ1_8R zOG6I1zNV6ySM6K;8@etKH8E7z!7PGc@YWXKx{338L7c*xqTvpWqHKVFROt#A`2Q=e z9Ek~WjIQLsr111>Fg*j4GMwMh5f|bIsxOP_N#T!;+w%7F0}BRn7{y{X7>xOR^(qf! zt#pGC6v03YK_v!opn>}bf`NtSX|{#B)^Z%D+nwlwtrewc4aT6kryoX<3)0=mG2b@s z55Up0T`)O4!*okcSs|>-SZO(S{pvh8h*lytb!0O&WZmhG;XW>s1LoOLkgX@+iTe4O zY0QIbjl%_VNb#4N+95DAqg;oA@CusA3nO03@x%dHD^ugIOqg%Y!txNH``5ZH&p^N{ z(QIv7rvR_sFV4w?QMBo?bU|nTFms$D+p*Se#t~NSs)C%@#E9_iRIk!BURb6GIMD&B zD9nZ8>U_-|vUVzW*p( zoScKInp#ND%CV;Of;PWPKtO43HoSZ5M&<@Dv=Jw$T#yl=3lh;35)yg`M-96-W%Wbj z6L4YJ3%QxPKG?s1KRoitBii-as%p65=38Oirp+3)Wlc}X<{cv6T`m~`@2JI(?cA~` zjGpZ1gTVAGTS)7?VmMl#O&_LIAu`;~g(PKiup+kpEb6ZcJWPR=WYWUD6?}e<~ zeDwT6aIUKZhWgKgcXR|M{Sz=ZJF5WbaDrsBEe!$dit`rDQhBHdFOH3~^AY5NOOpX` zCncK3Brz^XXB#Drca=>b_|awVMiC-iLan*E+44KBr%u8*KldppzN!NHI@(}ndTL4j zhPc=Xv*?}vuZi%Ze|%&&L*X2?H%T5N-I)yTaa@!lQ}*fb1lK(9JDtzE*bbm zBY-@;zrXT296s3s|9rg}PIaBL9LKiC90PqrqbL&5+MT$dFe}|aeOW_>7r!&;Rcyc8 z?Y^wR!$l$B<)$|7xyhWmLu>;St?AQsm4rW}^{v{P+$=?5$p$;ik)U!;RaMoS2LWTg zNgj>Sl^0PsmV+eoU0na@xTVXxA~_KwW3A;LIYkE13vMY7Z1apJ$v3f2%x>XCa;`YQfAs%)J(aSYm&$NfA$SYA&ExWP3J|O<3%gw^-qC6Fva4D6fz@!gF8^EKM?7)9BQ`VkcYEl9``|y3R zqiT(%?-8qAnw(l12hgG@$JdLtetk(HQ-W5J8?S$ovA$JuQ_Ju17t--~TMziBr(s~s zryy*9zdE76|P5<|GfErSpo}Ginj$U+wPr!-xo~UsS zp393&S&=N0a#MN=UMuoVP7WnQEK^(f<8UQJedCsEYvG2?m3(2i>E8@iv~hrlbT|E_&c;yushF@xsp ztjuJcH0*NPTPoKu?QBG>n)6e?Q?aooV(V*&BcfIh`gJS8&PC~RI6{V0HDBxu>I2dP z6bW8zBe%A_y`3F{-cjg4GpnV?HJ?HGPIi8gX>Q-3VbkRw15fQWFw{`b6qToTE4z2u zJV9MUE4``vJlo@wJ-4b0Q01MXJLEB@@tt8?TN{*>l|f=+B2=O%`TzB*#sR)@FN_Th zLKxYa?yX4AfP#`T=<94_?;D*k_yvQVQ2g$jAc%+z%}hhtt+$~ae$tHW@dS`Dn8G**eM)s`Z>=`BbiBwEZ zbwgfpDa$ykdf>Ku?uSPoxQ9i4{_w)9u;-)igJjAtqRA7Q4nf(C?^H}x%aLfmWbZ*J zs;PjYtIL;(0Ejegl#3V8nJI`Gd-QB4OK(T|0I#?AG6Xa{&Q6U?nM@$C z>JE-{)Cm;uy!p<%;m?o%5H8{d>+T=^4u1W`kF)d_Obp|T_nYmtsuNI5-}2G-fX!}) z;5_J0(kg7;^>zq_ zL$L3OpTlntyv%%($L_lW(rGUeBlp*Hq6OSp>2L`Zwx=YI?DR5IW3s+Up-$y-QNhw+ z5JD)wOq&}zrM9lCSr;{a7-clfDmu6YP^&vMr09LiuIu4r4}1;WX&LaBLk&=R>x1y% zFP?TwzsTkEM4;K|E}%xry!SX#LO9{AqlaPpNSaJ=pie0T2wc=S)tv9MYd zI!P2|rof6DsZB{7+B7L#CNqV+d@Ep3f)wkwYVX;$X+frEc-#lgJ?AyV0v7=~Cxusc z;28+pLU8qUyI`d&2TID_J_0%RQt8Unc7)}QHE)Q5;`o^NP`-yeJlremNDS?Fm!3li92L(N;!d`i0L(AN6Mi_5Apj*9>) zW>gj@n2?|_P8go9I|lilbf_rKV@G2SaL9WJj<aoMDyh0c}-^dW7XiMpk=7*l3XoYbqQJ`4SP>&f0^O%5P%i~TtYimb6gL~w+7V^5kxta^ z4}2Ipn@_`Q&%FqVsVR_!8h>=WA9|Wvz-2&q%8E4Dv~xH7K*cH%H63scB-Ni zEjd6?%B&=ugcekAAk21LgxGcZ#ABt^o4=vhRA6POBCAi7d1Y2i-D$-F1`pA|1yMuI z98|XcYPj<&--0v8>LK8tfWU;0xw*;im2j&52>85XxD?U!DMMM`Z_w=?5QwOP-~d*4 zDF>NPE6X99#tAC$*y(LFin3aJAOFGO+wT41_X^9aJ|&1^GL@gopqHYlCF-#NRDXr2 zXHmvB1_rsKmAwjf-uOZD-vp4`+tS1k5IK>`_D~FdiNOCA;R*`^LkH1L_2NQC4$%I@ zgkCR@4ibbp1P=G0vh>HFeCMeR*KBXRs%G2HyrR`x=Ym0j10tBpkO;dpU8gR;FLNx( zrZVpM##cQTv@hu|;I(lA1%=pVM@9!qo|y`$^SkQyKlK!X+>70hbEXlNAn2)GEny*; zgP^SZS)z(mypZrAiGm9UCgUVZ0w&>o+5_8Z94M8kBF&>nB^8Vsj)LJ@P~=aqW#>F3 zL`#5dNEWkmVpXORXpg8olUaNf^kayr4COgxWhrAji9@jq6Zn+?erN{A24yx@4)M9N zB^8uEx=@rM9*9dEq*!?;)oLSg0R?zLQ7k3|2rP7~Kq+!?jm65^pLPhw$^f$xkaZV< zp(D&~19JyeghU{Mj>OvJ7SaY_iX&qdUl3A}2@7CD3!E?jY}`U{s%u9<;hreK4JErm zWW{Y<5ioE7=Lp$=6oq;bM;#GL4{|vV&j;92TKv*sg?kKoQqZ4ibK}|%Q&!F3A;=M| lA}>IXTxnNYoc1391^_R-?9ht_;&%W5002ovPDHLkV1n|sV=Djv literal 0 HcmV?d00001 diff --git a/vendor/assets/images/authbuttons/google_32.png b/vendor/assets/images/authbuttons/google_32.png new file mode 100644 index 0000000000000000000000000000000000000000..3909e9de93b22e1f3a2e6c264f6289331412a3bb GIT binary patch literal 1615 zcmV-V2C(^wP)8wQ zK~#9!mVSaIA|e!R!IoP5D#joQpiPJxY7C7D!NjNpF-l@8 zi1DY2NsWn#7!t$;1BekdAhv0w)F>aJ(w2_~X`x38y|#DI_If+x?9Sfa?)9z^ewjGw z+jn;Moqe8pKW65D|9c~M`R;BSzax;AmX_Q_ix$<3?zFm(enng70IKHaVfVYs9Cke` zAA{C+1)Oss;zLA2a306vJdRB`f@dSquh(7;T~A41@7}%nwY9Z}RaJfPt*`#VzT>?h zlo%ijW@TZ|rbm(Ka~Zag&UOUWt^j8eRkx7@WZxKvd*yW9_WhmkrF)R(b;Fb9#_+fXkBg#m&U863HxK+q0PNCvC@vLLQG`%X zl}ar{Cr?OBjMe5(qhxsJ@YpdJv;?S)fEtNJX6T)xfA_;HfV~E|OK6wT|L)H|gvO%Q z1mCLXLDRjUUXLY;#|6c$3Q`IbRj~*WDhXZAyl1f;*G>S8F(V{Y7%F0tq7b;mM^s(J z>PMp-EnPP(dv{qSh*&*wxujNOqJZe2x)@70y`X4}pt0W#9!c^hf{&3JXJFde_=d(o4wqQ@uJq-iMa52H9ZiscuE zQ4}1v(QsCNN&;)EXW^$a{kS#~G3Uy9e_~#a@qRFP4X*`TaOmYyjOdlgG-1M|)}m<5 zcLPxk+p2O=bvcAL+xoHOa(EJsBLqLR{$ut1UKO9OE5m(x>DFfRVpTC#mKR`X;ufAd z*@$loRgAbP;&F=YMDbAQe{F?6)U7JUtIG?}m#(DtK*P>I(9|8p$Lp71W{wYq*=g9d zVKMrK#*Ccs3(>)6|ME75BVoB>W7W(Ak3I9a#7K$1BPHoLvbqR3dp$V;JzHBl2C!^v z6Us#;l!(fJ}G<232uotwFht;59nK^Zpbty!A*Ve zM4w~Q#>NoBUKp|=XkMUbty_qvQafRC*|Q@JF^l8T${1% z@OvhZCbeewj6L?r88|%f<>nf+?RXBaJUs_X3eJG_ZUnnf19plS!UJ0!lWX!9;{Am$ z#KB|LVD|#&PA?>EL=FNK_s;;24uPF62k#OWkp3M&s5xHdSGR#(tTk+`a4dK>zH&n} z8@SyQ$uC9@0v>w9&)Nk*__RE&xp`{GM1Kx`4}Px3nv?C$K#6ZgLj3Lh)b5`|AT#vE z0~lEODrljcep(blubI%E90w(4F z=Sfb?WM!DQMx2)=GTzJvm`Fkh@s%5MntD&#Vy`*FkhmAzZXYlP9y%Z{d|C1$shJW@ z=o9h2XroNR=Fd!EbHy4@vI*G$GCV~o35<@@E5u(8T5$>_f1T3b&R&Z~N{9=iDztaY8;@6P`C#`qK7Vn6RW!jS8~bu` z_shnm;j5@Wv|YyDsw^JwC%QZKJf>YFd%Ejsceq`Q+!ANbguE_N;-Zv#gkjbr)z$MG z8XDG=m6cTs17er%Yhm)uiB__!{YN4{N^G@F%wHh!y5WRa{aZsPkJF=peYAJ9Q`ih~ z#>N@v5t}QFrV1dx81#z)HzmX+#uRnGZX zkdUy9GS1i?{Wdgc8UI10f^p3y33JVRtGu{z`8!FHaU2Byz4osF0|3bfn|->$iJkxe N002ovPDHLkV1hOX`1Sw* literal 0 HcmV?d00001 diff --git a/vendor/assets/images/authbuttons/google_64.png b/vendor/assets/images/authbuttons/google_64.png new file mode 100644 index 0000000000000000000000000000000000000000..e55f34f1b7d57c52172eb2bab0964037c532629b GIT binary patch literal 3446 zcmV-+4T{|_t6~!I@&+NW;-}g8UPwu$$pb8>f^h8iZ;~{OqP*IR*tfDAr?C$LT{`3EwnFnyOTr3yM#qtF%D9d|Mmd|`1g-A3k48W8$N-tF!3+uf>d|R%_f6HxP7RX@ z_k0!l+m4A3C*nu==MZAI6I-B(hauK8G9QR@ogNSb$sHH^?tGv&-s_)+qBdOlwS;Y1N1wBTdv;YQvn_<}qVD8vx*KtaDeLTcK+UE-#4x<(*Vd zhhPB7lmVvb7rgrFt544xQSchXDfk?-&f&-WoYpym!9k*~Vt}@A;lff` z^v$yS&^bQhVw7V#AANp~8E`HYTsq#~dlJ&rRwzZRyb^NjX4{~Vmvl~y2@Eh6Ou)8k zIMRV7=|HwBFySDiSi*@iWdKg6(|JD8r7vfs3!=xmAa;&9Sq$mwGhoYsGr?AN!Xz80 zLmDTI*I>1o=N4eis~XJu3rRq>dTKL{b)V&RB(ja5`(qs@0E~nXV>kG?5y?#U-oy=VQ)@CJ z%%UG}IOf@eLWI*t%qv>P&U9_aYUE5{o>RC#J4QvUEweZMu#B-}FF zKRnzq_&5~#kCCcTx}xaz#9$cE>utEQqDYC51Te)aEho>1N9}=~dG4_TzwmIMWFgd9 z#r3mlF0s2Os@D)#U}l%jZnY=qKX@R6&|Xys!&QaU!^eQhWl)%_yFP~~zk?_l;bXv| z1MZ$eaFU?$%?|GnjUX-e-*g$g)OZ+}r82qA3>K0Y;TaLNtZ*IMyW5H3i68Rz@ER4vS0r%1HcFhOJn2)#BR$+CCmEh1{VU9l>?%MPg7&IKV zp4(ntz-Zg(eE4K!4y0mObZ#=h5FHx!`J_`9;KpN}FrCuugQ?)`aJU&zlox}q-&hH& zwzN8~%llplyjiA<9pTOhJJZm)@|UoU0$zJX32dk?f>az!Ac>p2YC>sWX)f#=8HZIh zB~aYe$C$8q$7vXo>iyqJfLXpdYaHyM{=Ml4=R83QD=m(%txmv%(S@$(SFU>!p1!>j zjuyrwkY0070=xn7S=$uNOJ2V+0k4lQf`!c;@V%X9GG;`m5#081d*HQa@2!FHqYE6c z#L{;MyeaxiZoAy|T>b7<@Oa5d2fY0-adLmJWhE-N=W#jW@*5M1;r4}9u)1c%&>8U1 zv+uD95TzF{41?nmA>8A=u!dVW(HBY z80Wq;m58UNkAnNZR>4&(%PBF_VwqokY1v(?50sV`!*h>MhdI|)1a^|9e%_4sT27p& zZc<}9FN?hie&+knz(>heKPZ*ngWP5rL2+(+1nb;7HoV6UjY;;x@u!dP*sx&me83JAseP6qLzh|U_jHJhI952*| zU<8R3bP{-X?+IvZJ_FTd1#rXoQW#U32V+X|pnOCww0Cr~`nqv`y=&@dh37wgCmf`# z&%~<=QakZ5O*s)xvdT50y?}V3<=2m&?SeOVwXu93OS$(Szcp3)`1|@zEsYJd&iSQ-y9AGLfXBy!sQx4ol9g9ALEQxnPfGPfs5?RtkYe6fxRrh z`hKXpWTF}{ctt(LNO}#Q>pHmAWH_=xw~>`c-||q_;ss#_GN_D*7eHg(&tUQRIc}E+ z*@(YqzJRE5Z<2Lp6v_ZTz0O745_PjSJmPPj|8~=%P$^)NQ2QXPzW(tHz#EF3!0>4WiYua!Ir&>^K>>%R-6~h>ZP?MW1(?Y1I*m?1SESpJyPIdf}yhd zD#PfJjNxE_mDt>Ub2Z#HwF>4;sTj6(?AnrX@bdKUz=FnQe8nnj7YLptDnJ4vm=Vf= zdv6^NKf3o?s4DaOcygf$;Cv&HE?V~5fWy!Rdj12!Mq zqXut;sRIlt2FQF}AV~BLMI1mfIPW>^o;Ex4AOGB-H`Z6Bz+N{OIA1W>Y_M#;-?OMj z+6a*Z6&25PPn#XwYOnuA206Y|+LQT_VKRb@0Y$X{C3XHO`%Hlv0p|s^&Xjpi8kX;Q z%{|Q>WD5*M!sC*F?31C$KnPEw0gRsTPu3U#dhQ`&xHDZSUkpfhW{;Qec^#77smwxM z2n&p|2Or9S?jA@pDaacOcnbC1T0%Wz6_mys3U$f922iz=AT^zCfu$d;lE7x-0u{4C zL7>Ut=LAVhE9@uz9kwdq>#5~V)J2PUkS(C#@imS1=r^5eftl;R>wuR-VI#^GfO?8d z1sLPhpd?`464=puZp(4o9#Bcps3hRp_W(-o^t-_zR~WAbbmeN$rZ!37|4qSvTZq2l zU+Pj$j;Iz$LPpwZOZ9FR8LpEk0``^{Gt-1W%1XJwtW`=?@1;h1KGnsDxU1`V1N|lN(ZbUU2ssXxP4rf=@?_D}nHh4^g5|pc6Kq-`xDqnwpy8L?Th9X<9r}&>eJ?*X-K}OE&!)mTr9!j&!tTmbrO@p6u-U zdHAenD}JZ_Nxb89Gr~AY0d-M8eJVvojt1CFV3GiAhc#6N0>xAkM$jAc>0L3lIi20Z zYQ9?+nfk?QY}ITBFG750Ex*^=;EokL9i1qH5NjFI5GTw)2$5yA-DUz}=X5l!WBxZ8 z^A8ef+HsP;x0BXAw7ri%OI5(^i$6mYTWr~fY9>e!{~8gLYlhB8I@j#9?H{ z3&==#3SEF_YT*HoBqs3tk@U9)*X~s$?`u|O5rnvNPePmk+yT#HQ7;oLDG{SWh<6itMqZW#TQ!_xkR)W7b`4%E7t0r}{8xYh Y0PP3DX~$FU?EnA(07*qoM6N<$g6|lC761SM literal 0 HcmV?d00001 diff --git a/vendor/assets/images/authbuttons/twitter_32.png b/vendor/assets/images/authbuttons/twitter_32.png new file mode 100644 index 0000000000000000000000000000000000000000..daadcffd315f11026cface9d99409997050ab9b9 GIT binary patch literal 1439 zcmV;Q1z`G#P)Y_}bdkmx`I#UBDP81NhfpbG&U zJv0JOj1Iv3@;aQIy#*$Uop&g^WHcK^3)l?_0n+>QjH3I@o%-Uft*pVYm8R%O=g{zn z0tH7WN8sh@gR(X;)Gzawmu}LBjU%Pwxbn1egKk(bDkWR-p@I8Zo4N&n!Iqp6I68o- z(LF8OG%?&yz_fEyWzectT4Tzdlt;QyY~=2MmN+A{z);<@S5asvP3SBEWi%)vr!qE0 z1qd@=r5JKlpbY@C6)>C2wASU_J(VIHo7xYU*c9Uj4Ei(#xUswj=l{G5Ks*tL5VJAL z2cWb{4g0z2Lh~4`6yO-~VyB}N2Jp>qHJ@#{+tA7Zr#Iq>pAmPZyU$V9*bp>#6T4v0 z?Js)evLe%U1A02HEUZ$9vc|D155jKsB9&DE11^TmV>3$Nc74-1a_zGthtKUw2!hx+Pxzyn=8Z<&^3vYEqL7qF zl6r5!rggy^cBu_%D(*x=%*0;2vDNJAV!Z>v>(4v}mHrB8Yk_jE0IHZ7Bv7DL%6x;S zm5li$giKYl+o@s&7i!CJ{K-dKo_ls|SVp(wySY1X^4s5Gb#)Ce_PWwNTRL@scObF# zoWl@NEbp$Y!`E{QJ*VIckMD=qj!fDT?nSM`_Z%JYArLk*p(q6Lb_AdPG7mRa{_YvX z_;587dd$s)P9Z{{PKhu)Cbl=W8}NX3;l!!)aQb4cCje(IT(=p5rlqCZISVo*z` zYWF7Pv?4H{{P+iae(^dS9@_`Q)pDlfLh9u;BJH`$H>qifQXRmYg4jVq^yy@KIO$}h z>EK3%3k#vz-q?b(OAn;F`D)h$Z&T0E`&=#2wQW5KQ4&Y>l!RcLQI#~2x65gJjM1mE z6E7>nUZkCksIi`{%Ym|uNJuJJ-dtV0KXmA+7j+Qs^_9?Mgvpr1HlqGoJWSk-X?yOw z=63auw>JK|{MkqEH|k3()VPS2N!LbwK!HG%=&gZ=4^B>vKmW?B)uGYJa)0#^>BR{# z%FKN^M*~$3skkL_;Z|rjkshYCd$p@S&Hr%v)Y|Q9S7?2eoY*D@8|hXkdxT`DN{dxm zDAKMJXf5D%H}lZ8Y{;y#{FO~dltiMLN9^W^Zb$SSOX?bv$%sbx@V}wJl3z+$Wjj8w tU9M`YBd+9ILRkF~K+PWazj*v3zyKvCC{2!YO3?rS002ovPDHLkV1fr@ymbHo literal 0 HcmV?d00001 diff --git a/vendor/assets/images/authbuttons/twitter_64.png b/vendor/assets/images/authbuttons/twitter_64.png new file mode 100644 index 0000000000000000000000000000000000000000..68b74530c06b558b6c4848c2637d4caeaf4c969b GIT binary patch literal 3384 zcmV-84af3{P)|0%I9Y+;DGrRXDwv)KA;{-zf6jEA3lT@ul+6P4XQUxkNMSZP=5E3suAS&^I z-~|vr;sNoFgoIRy2zUXC3aBbks-iZeDp5t#Bsfvh#LZ9b*iP)&zB`BcIWu!+@4eo= zH+DcuR+_tiv%7P?bLRZc&EOv2vikts2jD&c_w*)u>??YF=6|svYbyePBuQz|UjCmG zuXJ0|t)Pbe0$}dtx;6Jb`;7<3_B{ISH3LJRN5o+v1PCeI!$O44`kwt-xK8J0Z=Nyt z>6C8!>w46v+DJh^c6updTZe>lJEt=_T`VoWGZ)05}l{nCjSe{@`*-R=g0SVrsz4t()zk8IiZ*}pUzjp0Tk2fc^9k%0jsvmglj z1|th`&?F52>EIYZj`I+X+nakW+f9Ln$^o{WoPyO@AFHY$0l6kVlNtc&Fbo7+LOmRUIA=!ZrvnBtR!R{_QBqL3fve8M zfW^VzH_!9F{8@cZIc+e!e*50<=%cUe)~XADAn_l}*9<&u2sYd|#5eUm&t(LFiN6(T z_Y;61QZ=zm+?AIGnTW0`O#yq&5*fLxJkjPIO4w(FB7%i`chEcfSP2DrbMR@Rr=#-j z27r-(rVw&i(!94oSmM0|2rU6l2YA&dXi6ZPS?GyYoMIGN}N~Hf*_@` z_YCnu6N!cq1_V$vWz1OIG}B!+FyckoDs%(D>HzZs!|99&Hph7;!np&$JfOSlV+__o zb63!$P)>QN!f_7^X-Es=96645;2aDooJdP64QPon-?YSQ!X1&qaykl}ezzF|l7e>h zHoIy1d>Jb+0-hitBeD8NA6oI3bkAD@jfy?iKd@_boqfr~^c>7Bv~=G>6R+%Gt@sKL zg4Y9%Yi>G_f>e$lR>Gv4!OB`#Nn?p1_y%mxbo_{JAM^@9bp3=^bt1WGc`Ym&AdFRz z89cFj3=Zwt0&5%5%YOCD6?o;n%Wi52r_}`-sc{r}1!}nFNv01#m|*C~0f7;r(WDF4 z`ACJR^zyoGliZ)gZr)`WjI_ib{^Zt#c(XnA;1+o1k!>JyH&rZPz50{Ox@;mg)>*_E z|3NZG_=+PHxu@Sc(9m$5|B;EYAl* z6cbMlN+>&y?iyX+#`*HLacC{+i1z8!sUZPe8L}Ys693fK0oI4-9}%1h7$&4Qf0dDn z1xu3ha_7Q3N{JiAK1#1fFW%uhs*B`cPcY8@R69me|U`r?131e6Y#UoZOks8xQ(RAzvgGh@<6iN?~AD=P_H zC7q{7j)3zwtl1#O2m!dP0>R4Zlh+BcF^R~+>=c}f>H!mO2gi*ZJ?QZOBtjw(a;@ohJ7i)@Lq-hPgsPM*WILE zZ`Wt%L-M07501EUO3*tU9Ej)uK@45*A_i|=oP?`0^De)jd=>~&FnX{EvdR^X$xSR} zaO*j0>K6R+wNs#$S}wPMD&!pzO3JXNHK=rjfjK}C1W2;CSZ}()iOV-&a&D1X zlGL;&sc=Zs;@4(x!?Dv7P%JJ1whEgE1j;f2&jltH2`fXC%3z3_KCb){5Xe$gZO7lA zg0oj=ocLN1R+J2lX)*s^#j?PKa{UWUxGD;IzG$l()YN-DC_!%eSX$c-kkCa6TI$RI zORy2$B~3)D6|%hLT0jDV0id8XxP4v|-cl?Tu9)eI`k<~}u zrW&+F6^;mHxTzG&7DwV0#)^-!2~{H0^fk{1$zjtF%0y!=iKsM#QQODCNkTwTm@0e# zQ?YGa+a%5H2vEe;BtzU*3~|J(Qqcs6DP@ne*O;Kv3AeW}*DnGXGBg2#wl`bh_vOm(Nz9c19 zJn+obWoho8 zKX~Zlo8kFS?}ovFH6R*!Y`Jbt*C1SP*e2<|0mXu0BnVjIv=o(N55Z7nMu^W(F99}d zqnwQ}n@xZ&1MfL`{pM}>_vI=0`>9K|K!P?QqC(Bk zkC7>b70L-FDR-uk(G?>t`c?v5e(&uIlknmG1sK&KYn|;AW9w@Ua~M9eXA2zu)HeA3 zA5Or`?416tNr)&i)uKc8s-7bt>o`KZHXkLy*=REb3S*nKT{oWEuaA$fS}d@0bRE2K zc)!yTRA1=mmg5TP0G#2zqCI0H{Jd9tN4$EgkY8<=NbneUwL{vTZ1;#3k07aEvsu3D< zU~2!yL~6w-@&aCb{WKgqGXc*&x)UDTK6+=I*Ur{Y|NOR|YAzvSLt^d@m)91qj32;i zfQIwJHCwH*?kbiNDBvo=X z6^^`d7RDzgt)yAvLqMcT>kC)V5sG0cP}E0Gh%M8Jv?z+SV99)0bI6-2Vd`1hdz)BT zgqN<*z@NyMZC^+k{d(oSP(^D5Y04oHZ_F+ajQTYMH4-8vZ_uvBa^jz^%81Z=(shDxn~LLk?UTK>4|eiv9$Qk$gaJI3V>Do z({vSI7KRBXz5WGGw3kl< zNhCae<&NWaIELW=EcfknX)=?9Fg4;aFbP5EFBrVP-T&+Cy$-;C1sDK!FMbnQfbweq O0000 Date: Fri, 17 Aug 2012 16:32:22 +0200 Subject: [PATCH 002/123] Adding default values for omniauth settings so tests don't failt --- config/gitlab.yml.example | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 622ac9ec..85149fe8 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -51,6 +51,10 @@ git: git_timeout: 10 # Omniauth configuration +omniauth: + enabled: false + providers: + # omniauth: # enabled: true # providers: From 36ffdf36b96a877154f265327d83d022ed27e9e4 Mon Sep 17 00:00:00 2001 From: Florian Unglaub Date: Fri, 24 Aug 2012 15:40:44 +0200 Subject: [PATCH 003/123] Merge issue fixed --- app/controllers/omniauth_callbacks_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index 9b40e564..00ec7c42 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -33,7 +33,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController if current_user # Change a logged-in user's authentication method: - current_user.uid = uid + current_user.extern_uid = uid current_user.provider = provider current_user.save redirect_to profile_path From 6d6c7a17ea2d2a61d4f251d6d746ebe9438405ca Mon Sep 17 00:00:00 2001 From: Florian Unglaub Date: Fri, 31 Aug 2012 15:45:50 +0200 Subject: [PATCH 004/123] Allow single-sign-on with Omniauth --- .../omniauth_callbacks_controller.rb | 4 +-- app/models/user.rb | 34 ++++++++++++++++++- config/gitlab.yml.example | 2 ++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index 00ec7c42..248a75a8 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -38,7 +38,8 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController current_user.save redirect_to profile_path else - @user = User.find_by_provider_and_extern_uid(provider, uid) + @user = User.find_or_new_for_omniauth(oauth) + @user.save! if @user.try('new_record?') if @user sign_in_and_redirect @user @@ -48,5 +49,4 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController end end end - end diff --git a/app/models/user.rb b/app/models/user.rb index ad6af6a6..b956d4ed 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -86,6 +86,39 @@ class User < ActiveRecord::Base where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') end + def self.find_or_new_for_omniauth(oauth) + provider, uid = oauth['provider'], oauth['uid'] + + if @user = User.find_by_provider_and_extern_uid(provider, uid) + @user + else + if Gitlab.config.omniauth.allow_single_sign_on + # Ensure here that all required attributes were passed along with the + # oauth request: + %w(first_name last_name email).each do |attr| + unless oauth[:info][attr].present? + raise OmniAuth::Error, + "#{provider} does not provide the required field #{attr}" + end + end + + password = Devise.friendly_token[0, 8].downcase + @user = User.new( + extern_uid: uid, + provider: provider, + name: "#{oauth[:info][:first_name]} #{oauth[:info][:last_name]}", + email: oauth[:info][:email], + password: password, + password_confirmation: password, + projects_limit: Gitlab.config.default_projects_limit, + ) + + @user.blocked = true if Gitlab.config.omniauth.block_auto_created_users + @user + end + end + end + def self.find_for_ldap_auth(auth, signed_in_resource=nil) uid = auth.info.uid provider = auth.provider @@ -148,4 +181,3 @@ end # bio :string(255) # blocked :boolean(1) default(FALSE), not null # - diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 1934029d..b5aae497 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -53,6 +53,8 @@ git: omniauth: enabled: false providers: + allow_single_sign_on: false + block_auto_created_users: true # omniauth: # enabled: true From 1b0198f1d3fc621b339af0e7fd79a74919856d46 Mon Sep 17 00:00:00 2001 From: Florian Unglaub Date: Fri, 31 Aug 2012 16:24:12 +0200 Subject: [PATCH 005/123] save newly created users directly in the model --- app/controllers/omniauth_callbacks_controller.rb | 1 - app/models/user.rb | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index 248a75a8..3be285ba 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -39,7 +39,6 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController redirect_to profile_path else @user = User.find_or_new_for_omniauth(oauth) - @user.save! if @user.try('new_record?') if @user sign_in_and_redirect @user diff --git a/app/models/user.rb b/app/models/user.rb index b956d4ed..0d45b6e5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -114,6 +114,8 @@ class User < ActiveRecord::Base ) @user.blocked = true if Gitlab.config.omniauth.block_auto_created_users + @user.save! + @user end end From 0dd94cd86ec0680432e58f2630a3a35fa84afd73 Mon Sep 17 00:00:00 2001 From: Florian Unglaub Date: Fri, 31 Aug 2012 16:44:23 +0200 Subject: [PATCH 006/123] DRY'ed up the user model --- app/models/user.rb | 69 +++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 0d45b6e5..fa5d6834 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -86,36 +86,42 @@ class User < ActiveRecord::Base where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') end - def self.find_or_new_for_omniauth(oauth) - provider, uid = oauth['provider'], oauth['uid'] + def self.create_from_omniauth(auth, ldap = false) + provider, uid = auth.provider, 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? + + logger.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 self.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 - # Ensure here that all required attributes were passed along with the - # oauth request: - %w(first_name last_name email).each do |attr| - unless oauth[:info][attr].present? - raise OmniAuth::Error, - "#{provider} does not provide the required field #{attr}" - end - end - - password = Devise.friendly_token[0, 8].downcase - @user = User.new( - extern_uid: uid, - provider: provider, - name: "#{oauth[:info][:first_name]} #{oauth[:info][:last_name]}", - email: oauth[:info][:email], - password: password, - password_confirmation: password, - projects_limit: Gitlab.config.default_projects_limit, - ) - - @user.blocked = true if Gitlab.config.omniauth.block_auto_created_users - @user.save! - + @user = User.create_from_omniauth(auth) @user end end @@ -124,7 +130,6 @@ class User < ActiveRecord::Base def self.find_for_ldap_auth(auth, signed_in_resource=nil) uid = auth.info.uid provider = auth.provider - name = auth.info.name.force_encoding("utf-8") 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? @@ -136,17 +141,7 @@ class User < ActiveRecord::Base @user.update_attributes(:extern_uid => uid, :provider => provider) @user else - logger.info "Creating user from LDAP login {uid => #{uid}, name => #{name}, email => #{email}}" - password = Devise.friendly_token[0, 8].downcase - @user = User.create( - :extern_uid => uid, - :provider => provider, - :name => name, - :email => email, - :password => password, - :password_confirmation => password, - :projects_limit => Gitlab.config.default_projects_limit - ) + create_from_omniauth(auth) end end From 06c1a8a9ae34e2a4fe7b4f4edb58bacfaf6df5c9 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Sat, 8 Sep 2012 02:08:35 +0200 Subject: [PATCH 007/123] Make notes recognize downvotes --- app/models/note.rb | 6 ++++++ spec/models/note_spec.rb | 23 +++++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/app/models/note.rb b/app/models/note.rb index d8494edd..4c46c7df 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -105,6 +105,12 @@ class Note < ActiveRecord::Base def upvote? note.start_with?('+1') || note.start_with?(':+1:') end + + # Returns true if this is a downvote note, + # otherwise false is returned + def downvote? + note.start_with?('-1') || note.start_with?(':-1:') + end end # == Schema Information # diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index dddfd34c..7809953f 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -24,6 +24,13 @@ describe Note do it "recognizes a neutral note" do note = Factory(:note, note: "This is not a +1 note") note.should_not be_upvote + note.should_not be_downvote + end + + it "recognizes a neutral emoji note" do + note = build(:note, note: "I would :+1: this, but I don't want to") + note.should_not be_upvote + note.should_not be_downvote end it "recognizes a +1 note" do @@ -31,19 +38,19 @@ describe Note do note.should be_upvote end - it "recognizes a -1 note as no vote" do - note = Factory(:note, note: "-1 for this") - note.should_not be_upvote - end - it "recognizes a +1 emoji as a vote" do note = build(:note, note: ":+1: for this") note.should be_upvote end - it "recognizes a neutral emoji note" do - note = build(:note, note: "I would :+1: this, but I don't want to") - note.should_not be_upvote + it "recognizes a -1 note" do + note = Factory(:note, note: "-1 for this") + note.should be_downvote + end + + it "recognizes a -1 emoji as a vote" do + note = build(:note, note: ":-1: for this") + note.should be_downvote end end From a2a0060034171e22962129d53cc74fb7bde54476 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Sat, 8 Sep 2012 02:23:49 +0200 Subject: [PATCH 008/123] Rename Upvote role to Votes --- app/models/issue.rb | 2 +- app/models/merge_request.rb | 2 +- app/roles/{upvote.rb => votes.rb} | 2 +- spec/models/issue_spec.rb | 2 +- spec/models/merge_request_spec.rb | 2 +- spec/roles/{upvote_spec.rb => votes_spec.rb} | 0 6 files changed, 5 insertions(+), 5 deletions(-) rename app/roles/{upvote.rb => votes.rb} (88%) rename spec/roles/{upvote_spec.rb => votes_spec.rb} (100%) diff --git a/app/models/issue.rb b/app/models/issue.rb index 6409eeba..96a54907 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -1,6 +1,6 @@ class Issue < ActiveRecord::Base include IssueCommonality - include Upvote + include Votes acts_as_taggable_on :labels diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 542817b0..3376e31b 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -2,7 +2,7 @@ require File.join(Rails.root, "app/models/commit") class MergeRequest < ActiveRecord::Base include IssueCommonality - include Upvote + include Votes BROKEN_DIFF = "--broken-diff" diff --git a/app/roles/upvote.rb b/app/roles/votes.rb similarity index 88% rename from app/roles/upvote.rb rename to app/roles/votes.rb index 7efa6f20..29409292 100644 --- a/app/roles/upvote.rb +++ b/app/roles/votes.rb @@ -1,4 +1,4 @@ -module Upvote +module Votes # Return the number of +1 comments (upvotes) def upvotes notes.select(&:upvote?).size diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index ca6307e7..34192da9 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -12,7 +12,7 @@ describe Issue do describe 'modules' do it { should include_module(IssueCommonality) } - it { should include_module(Upvote) } + it { should include_module(Votes) } end subject { Factory.create(:issue) } diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index d1253b35..523e823d 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -8,6 +8,6 @@ describe MergeRequest do describe 'modules' do it { should include_module(IssueCommonality) } - it { should include_module(Upvote) } + it { should include_module(Votes) } end end diff --git a/spec/roles/upvote_spec.rb b/spec/roles/votes_spec.rb similarity index 100% rename from spec/roles/upvote_spec.rb rename to spec/roles/votes_spec.rb From 2e0d5c2250ad34273a0ad6e207f2717b9a98bd86 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Sat, 8 Sep 2012 02:30:47 +0200 Subject: [PATCH 009/123] Add downvotes --- app/roles/votes.rb | 5 ++++ spec/roles/votes_spec.rb | 60 ++++++++++++++++++++++++++++------------ 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/app/roles/votes.rb b/app/roles/votes.rb index 29409292..fb132a33 100644 --- a/app/roles/votes.rb +++ b/app/roles/votes.rb @@ -3,4 +3,9 @@ module Votes def upvotes notes.select(&:upvote?).size end + + # Return the number of -1 comments (downvotes) + def downvotes + notes.select(&:downvote?).size + end end diff --git a/spec/roles/votes_spec.rb b/spec/roles/votes_spec.rb index 24288ada..43817999 100644 --- a/spec/roles/votes_spec.rb +++ b/spec/roles/votes_spec.rb @@ -1,27 +1,53 @@ require 'spec_helper' -describe Issue, "Upvote" do +describe Issue do let(:issue) { create(:issue) } - it "with no notes has a 0/0 score" do - issue.upvotes.should == 0 + describe "#upvotes" do + it "with no notes has a 0/0 score" do + issue.upvotes.should == 0 + end + + it "should recognize non-+1 notes" do + issue.notes << create(:note, note: "No +1 here") + issue.should have(1).note + issue.notes.first.upvote?.should be_false + issue.upvotes.should == 0 + end + + it "should recognize a single +1 note" do + issue.notes << create(:note, note: "+1 This is awesome") + issue.upvotes.should == 1 + end + + it "should recognize multiple +1 notes" do + issue.notes << create(:note, note: "+1 This is awesome") + issue.notes << create(:note, note: "+1 I want this") + issue.upvotes.should == 2 + end end - it "should recognize non-+1 notes" do - issue.notes << create(:note, note: "No +1 here") - issue.should have(1).note - issue.notes.first.upvote?.should be_false - issue.upvotes.should == 0 - end + describe "#downvotes" do + it "with no notes has a 0/0 score" do + issue.downvotes.should == 0 + end - it "should recognize a single +1 note" do - issue.notes << create(:note, note: "+1 This is awesome") - issue.upvotes.should == 1 - end + it "should recognize non--1 notes" do + issue.notes << create(:note, note: "Almost got a -1") + issue.should have(1).note + issue.notes.first.downvote?.should be_false + issue.downvotes.should == 0 + end - it "should recognize multiple +1 notes" do - issue.notes << create(:note, note: "+1 This is awesome") - issue.notes << create(:note, note: "+1 I want this") - issue.upvotes.should == 2 + it "should recognize a single -1 note" do + issue.notes << create(:note, note: "-1 This is bad") + issue.downvotes.should == 1 + end + + it "should recognize multiple -1 notes" do + issue.notes << create(:note, note: "-1 This is bad") + issue.notes << create(:note, note: "-1 Away with this") + issue.downvotes.should == 2 + end end end From 7b0c7ae52c299584e810fc4b1a33893ebdbb8ac3 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Sat, 8 Sep 2012 02:37:29 +0200 Subject: [PATCH 010/123] Add votes_count --- app/roles/votes.rb | 5 +++++ spec/roles/votes_spec.rb | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/app/roles/votes.rb b/app/roles/votes.rb index fb132a33..3a584d8b 100644 --- a/app/roles/votes.rb +++ b/app/roles/votes.rb @@ -8,4 +8,9 @@ module Votes def downvotes notes.select(&:downvote?).size end + + # Return the total number of votes + def votes_count + upvotes + downvotes + end end diff --git a/spec/roles/votes_spec.rb b/spec/roles/votes_spec.rb index 43817999..5c3548a5 100644 --- a/spec/roles/votes_spec.rb +++ b/spec/roles/votes_spec.rb @@ -50,4 +50,33 @@ describe Issue do issue.downvotes.should == 2 end end + + describe "#votes_count" do + it "with no notes has a 0/0 score" do + issue.votes_count.should == 0 + end + + it "should recognize non notes" do + issue.notes << create(:note, note: "No +1 here") + issue.should have(1).note + issue.votes_count.should == 0 + end + + it "should recognize a single +1 note" do + issue.notes << create(:note, note: "+1 This is awesome") + issue.votes_count.should == 1 + end + + it "should recognize a single -1 note" do + issue.notes << create(:note, note: "-1 This is bad") + issue.votes_count.should == 1 + end + + it "should recognize multiple notes" do + issue.notes << create(:note, note: "+1 This is awesome") + issue.notes << create(:note, note: "-1 This is bad") + issue.notes << create(:note, note: "+1 I want this") + issue.votes_count.should == 3 + end + end end From 1271b4ce66d4251f8f038d8d339fbecbab2d0900 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Sat, 8 Sep 2012 03:30:41 +0200 Subject: [PATCH 011/123] Update display of merge requests and issues to also show downvotes --- app/assets/stylesheets/common.scss | 20 ++++++++++++++----- app/views/issues/_show.html.haml | 2 ++ app/views/issues/show.html.haml | 6 ++++-- .../merge_requests/_merge_request.html.haml | 2 ++ .../merge_requests/show/_mr_title.html.haml | 6 ++++-- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index aa27a280..d52cb1fc 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -406,13 +406,23 @@ p.time { } } -.upvotes { +.votes { font-size: 14px; font-weight: bold; - color: #468847; - text-align: right; - padding: 4px; - margin: 2px; + padding: 4px 0; + margin: 2px 0; + .upvotes { + display: inline-block; + color: #468847; + padding: 0 4px; + margin: 0 2px; + } + .downvotes { + display: inline-block; + color: #B94A48; + padding: 0 4px; + margin: 0 2px; + } } /* Fix for readme code (stopped it from being yellow) */ diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml index 8500cd40..e37ea3df 100644 --- a/app/views/issues/_show.html.haml +++ b/app/views/issues/_show.html.haml @@ -36,3 +36,5 @@ - if issue.upvotes > 0 %span.badge.badge-success= "+#{issue.upvotes}" + - if issue.downvotes > 0 + %span.badge.badge-important= "-#{issue.downvotes}" diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index dce8cf6a..36af1f49 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -17,8 +17,10 @@ Edit %br - - if @issue.upvotes > 0 - .upvotes#upvotes= "+#{pluralize @issue.upvotes, 'upvote'}" + .votes#votes + Votes: + .upvotes#upvotes= "#{@issue.upvotes} up" + .downvotes#downvotes= "#{@issue.downvotes} down" .back_link = link_to project_issues_path(@project) do diff --git a/app/views/merge_requests/_merge_request.html.haml b/app/views/merge_requests/_merge_request.html.haml index 74996090..8d0a6dcf 100644 --- a/app/views/merge_requests/_merge_request.html.haml +++ b/app/views/merge_requests/_merge_request.html.haml @@ -25,3 +25,5 @@ ago - if merge_request.upvotes > 0 %span.badge.badge-success= "+#{merge_request.upvotes}" + - if merge_request.downvotes > 0 + %span.badge.badge-important= "-#{merge_request.downvotes}" diff --git a/app/views/merge_requests/show/_mr_title.html.haml b/app/views/merge_requests/show/_mr_title.html.haml index 3ae1050d..f8ab6c19 100644 --- a/app/views/merge_requests/show/_mr_title.html.haml +++ b/app/views/merge_requests/show/_mr_title.html.haml @@ -24,8 +24,10 @@ Edit %br - - if @merge_request.upvotes > 0 - .upvotes#upvotes= "+#{pluralize @merge_request.upvotes, 'upvote'}" + .votes#votes + Votes: + .upvotes#upvotes= "#{@merge_request.upvotes} up" + .downvotes#downvotes= "#{@merge_request.downvotes} down" .back_link From 5ca31aa252d67372d9a90cceb61f16721dca3841 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Sat, 8 Sep 2012 16:00:38 +0200 Subject: [PATCH 012/123] Make issue buttons look more consistent with MRs --- app/views/issues/show.html.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index 36af1f49..12394ac5 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -8,11 +8,11 @@ %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 From a5164ea2ed4e809cb4af7a070652ef2a6b19fbf3 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Sat, 8 Sep 2012 16:44:56 +0200 Subject: [PATCH 013/123] Show votes as a bar --- app/assets/stylesheets/common.scss | 41 +++++++++++++++---- app/views/issues/_show.html.haml | 13 ++++-- app/views/issues/show.html.haml | 15 ++++--- .../merge_requests/_merge_request.html.haml | 13 ++++-- .../merge_requests/show/_mr_title.html.haml | 15 ++++--- 5 files changed, 70 insertions(+), 27 deletions(-) diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index d52cb1fc..829bece3 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -407,21 +407,46 @@ p.time { } .votes { - font-size: 14px; - font-weight: bold; - padding: 4px 0; - margin: 2px 0; + 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); + } + } .upvotes { display: inline-block; color: #468847; - padding: 0 4px; - margin: 0 2px; } .downvotes { display: inline-block; color: #B94A48; - padding: 0 4px; - margin: 0 2px; + } +} +.votes-block { + margin: 14px 6px 6px 0; + .downvotes { + float: right; + } +} +.votes-inline { + display: inline-block; + margin: 0 8px; + .progress { + display: inline-block; + padding: 0 0 2px; + width: 45px; } } diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml index e37ea3df..db394873 100644 --- a/app/views/issues/_show.html.haml +++ b/app/views/issues/_show.html.haml @@ -34,7 +34,12 @@ - else   - - if issue.upvotes > 0 - %span.badge.badge-success= "+#{issue.upvotes}" - - if issue.downvotes > 0 - %span.badge.badge-important= "-#{issue.downvotes}" + - if issue.votes_count > 0 + .votes.votes-inline + .upvotes= issue.upvotes + .progress + - up_percent = 100.0/issue.votes_count*issue.upvotes + - down_percent = 100.0-up_percent + .bar.bar-success{style: "width: #{up_percent}%;"} + .bar.bar-danger{style: "width: #{down_percent}%;"} + .downvotes= issue.downvotes diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index 12394ac5..1ec03951 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -16,16 +16,21 @@ %i.icon-edit Edit - %br - .votes#votes - Votes: - .upvotes#upvotes= "#{@issue.upvotes} up" - .downvotes#downvotes= "#{@issue.downvotes} down" +.right + .span3.votes.votes-block#votes + .progress + - up_percent = 100.0/@issue.votes_count*@issue.upvotes + - down_percent = 100.0-up_percent + .bar.bar-success{style: "width: #{up_percent}%;"} + .bar.bar-danger{style: "width: #{down_percent}%;"} + .upvotes= "#{@issue.upvotes} up" + .downvotes= "#{@issue.downvotes} down" .back_link = link_to project_issues_path(@project) do ← To issues list + .main_box .top_box_content %h4 diff --git a/app/views/merge_requests/_merge_request.html.haml b/app/views/merge_requests/_merge_request.html.haml index 8d0a6dcf..08420fd2 100644 --- a/app/views/merge_requests/_merge_request.html.haml +++ b/app/views/merge_requests/_merge_request.html.haml @@ -23,7 +23,12 @@ 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.downvotes > 0 - %span.badge.badge-important= "-#{merge_request.downvotes}" + - if merge_request.votes_count > 0 + .votes.votes-inline + .upvotes= merge_request.upvotes + .progress + - up_percent = 100.0/merge_request.votes_count*merge_request.upvotes + - down_percent = 100.0-up_percent + .bar.bar-success{style: "width: #{up_percent}%;"} + .bar.bar-danger{style: "width: #{down_percent}%;"} + .downvotes= merge_request.downvotes diff --git a/app/views/merge_requests/show/_mr_title.html.haml b/app/views/merge_requests/show/_mr_title.html.haml index f8ab6c19..c0ad4be5 100644 --- a/app/views/merge_requests/show/_mr_title.html.haml +++ b/app/views/merge_requests/show/_mr_title.html.haml @@ -23,12 +23,15 @@ %i.icon-edit Edit - %br - .votes#votes - Votes: - .upvotes#upvotes= "#{@merge_request.upvotes} up" - .downvotes#downvotes= "#{@merge_request.downvotes} down" - +.right + .span3.votes.votes-block#votes + .progress + - up_percent = 100.0/@merge_request.votes_count*@merge_request.upvotes + - down_percent = 100.0-up_percent + .bar.bar-success{style: "width: #{up_percent}%;"} + .bar.bar-danger{style: "width: #{down_percent}%;"} + .upvotes= "#{@merge_request.upvotes} up" + .downvotes= "#{@merge_request.downvotes} down" .back_link = link_to project_merge_requests_path(@project) do From 3b5a90bdf654f9715fd15c189d59bd56492bae8c Mon Sep 17 00:00:00 2001 From: miks Date: Sat, 8 Sep 2012 20:51:12 +0300 Subject: [PATCH 014/123] Projects hooks API implemented --- doc/api/projects.md | 44 ++++++++++++++++++++++++++++++ lib/api/entities.rb | 4 +++ lib/api/projects.rb | 40 +++++++++++++++++++++++++++ spec/requests/api/projects_spec.rb | 31 +++++++++++++++++++++ 4 files changed, 119 insertions(+) diff --git a/doc/api/projects.md b/doc/api/projects.md index 72874e59..73d6adc9 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -173,6 +173,50 @@ Parameters: Will return status `200 OK` on success, or `404 Not found` on fail. +## Get project hooks + +Get hooks for project + +``` +GET /projects/:id/hooks +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project + +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. + ## Project repository branches Get a list of repository branches from a project, sorted by name alphabetically. diff --git a/lib/api/entities.rb b/lib/api/entities.rb index fef5328d..b50d683f 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -9,6 +9,10 @@ module Gitlab expose :id, :email, :name, :blocked, :created_at 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 diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 7da83429..876de321 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -103,6 +103,46 @@ module Gitlab nil 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 + @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 + @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 + @hook = user_project.hooks.find(params[:hook_id]) + @hook.destroy + nil + end + # Get a project repository branches # # Parameters: diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 439aecce..23fb34e6 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -6,6 +6,7 @@ describe Gitlab::API do let(:user) { Factory :user } let(:user2) { Factory.create(:user) } let(:user3) { Factory.create(:user) } + let!(:hook) { Factory :project_hook, project: project, url: "http://example.com" } let!(:project) { Factory :project, owner: user } let!(:snippet) { Factory :snippet, author: user, project: project, title: 'example' } let!(:users_project) { Factory :users_project, user: user, project: project, project_access: UsersProject::MASTER } @@ -147,6 +148,36 @@ describe Gitlab::API do end end + describe "GET /projects/:id/hooks" do + it "should return project hooks" do + get api("/projects/#{project.code}/hooks", user) + + response.status.should == 200 + + json_response.should be_an Array + json_response.count.should == 1 + json_response.first['url'].should == "http://example.com" + end + end + + describe "POST /projects/:id/users" do + it "should add hook to project" do + expect { + post api("/projects/#{project.code}/hooks", user), + "url" => "http://example.com" + }.to change {project.hooks.count}.by(1) + end + end + + describe "DELETE /projects/:id/hooks" do + it "should delete hook from project" do + expect { + delete api("/projects/#{project.code}/hooks", user), + hook_id: hook.id + }.to change {project.hooks.count}.by(-1) + end + end + describe "GET /projects/:id/repository/tags" do it "should return an array of project tags" do get api("/projects/#{project.code}/repository/tags", user) From d6c384c20f3798fffd0481cd758700a27bebd44f Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 10 Sep 2012 02:09:55 -0400 Subject: [PATCH 015/123] Reduce the amount of JavaScript written in views Seeing `:javascript` all over Views feels like a code smell. This goes a long way towards reducing the amount of JS in views, but there's still plenty to be done on that front. --- app/assets/javascripts/main.js.coffee | 3 +++ app/views/admin/projects/_form.html.haml | 3 +-- app/views/admin/projects/show.html.haml | 18 ++---------------- app/views/admin/team_members/_form.html.haml | 13 +------------ app/views/admin/users/show.html.haml | 18 ++---------------- app/views/commits/_head.html.haml | 7 +------ app/views/issues/_form.html.haml | 4 ++-- app/views/issues/edit.html.haml | 7 ------- app/views/issues/new.html.haml | 7 ------- app/views/merge_requests/_form.html.haml | 13 +++---------- app/views/milestones/edit.html.haml | 6 ------ app/views/projects/_refs.html.haml | 7 +------ app/views/protected_branches/index.html.haml | 5 +---- app/views/refs/_head.html.haml | 2 +- app/views/refs/_tree.html.haml | 3 --- app/views/refs/blame.html.haml | 5 ----- app/views/snippets/_form.html.haml | 10 +--------- app/views/team_members/_form.html.haml | 13 +++---------- 18 files changed, 22 insertions(+), 122 deletions(-) diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee index a01b3932..86b19162 100644 --- a/app/assets/javascripts/main.js.coffee +++ b/app/assets/javascripts/main.js.coffee @@ -24,6 +24,9 @@ $ -> # 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) diff --git a/app/views/admin/projects/_form.html.haml b/app/views/admin/projects/_form.html.haml index 87d212e5..4848e739 100644 --- a/app/views/admin/projects/_form.html.haml +++ b/app/views/admin/projects/_form.html.haml @@ -32,7 +32,7 @@ - unless project.new_record? .clearfix = f.label :owner_id - .input= f.select :owner_id, User.all.map { |user| [user.name, user.id] } + .input= f.select :owner_id, User.all.map { |user| [user.name, user.id] }, {}, {class: 'chosen'} - if project.repo_exists? .clearfix @@ -69,7 +69,6 @@ :javascript $(function(){ - $('#project_owner_id').chosen(); new Projects(); }) diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 65d888f5..63987410 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -71,25 +71,11 @@ %th Project Access: %tr - %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), multiple: true - %td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select" + %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' + %td= select_tag :project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3"} %tr %td= submit_tag 'Add', class: "btn primary" %td Read more about project permissions %strong= link_to "here", help_permissions_path, class: "vlink" - -:css - form select { - width:150px; - } - - #user_ids { - width:300px; - } - -:javascript - $('select#user_ids').chosen(); - $('select#repo_access').chosen(); - $('select#project_access').chosen(); diff --git a/app/views/admin/team_members/_form.html.haml b/app/views/admin/team_members/_form.html.haml index 6a128de9..9cd94fdd 100644 --- a/app/views/admin/team_members/_form.html.haml +++ b/app/views/admin/team_members/_form.html.haml @@ -8,20 +8,9 @@ .clearfix %label Project Access: .input - = f.select :project_access, options_for_select(Project.access_options, @admin_team_member.project_access), {}, class: "project-access-select" + = f.select :project_access, options_for_select(Project.access_options, @admin_team_member.project_access), {}, class: "project-access-select chosen span3" %br .actions = f.submit 'Save', class: "btn primary" = link_to 'Cancel', :back, class: "btn" - -:css - form select { - width:300px; - } - -:javascript - $('select#team_member_user_id').chosen(); - $('select#team_member_project_id').chosen(); - $('select#team_member_repo_access').chosen(); - $('select#team_member_project_access').chosen(); diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index 4d2b9832..731916e9 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -68,8 +68,8 @@ %th Project Access: %tr - %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name), multiple: true - %td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select" + %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' + %td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select chosen span3" %tr %td= submit_tag 'Add', class: "btn primary" @@ -97,17 +97,3 @@ %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), class: "medium project-access-select", disabled: :disabled %td= link_to 'Edit Access', edit_admin_team_member_path(tm), class: "btn small" %td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn small danger" - -:css - form select { - width:150px; - } - - #project_ids { - width:300px; - } - -:javascript - $('select#project_ids').chosen(); - $('select#repo_access').chosen(); - $('select#project_access').chosen(); diff --git a/app/views/commits/_head.html.haml b/app/views/commits/_head.html.haml index a211329f..5a09d82a 100644 --- a/app/views/commits/_head.html.haml +++ b/app/views/commits/_head.html.haml @@ -1,7 +1,7 @@ %ul.nav.nav-tabs %li = form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do - = select_tag "ref", grouped_options_refs, onchange: "$(this.form).trigger('submit');", class: "project-refs-select" + = select_tag "ref", grouped_options_refs, onchange: "$(this.form).trigger('submit');", class: "project-refs-select chosen" = hidden_field_tag :destination, "commits" %li{class: "#{'active' if current_page?(project_commits_path(@project)) }"} @@ -26,8 +26,3 @@ %span.rss-icon = link_to project_commits_path(@project, :atom, { private_token: current_user.private_token, ref: @ref }), title: "Feed" do = image_tag "rss_ui.png", title: "feed" - -:javascript - $(function(){ - $('.project-refs-select').chosen(); - }); diff --git a/app/views/issues/_form.html.haml b/app/views/issues/_form.html.haml index 23de7e8e..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 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/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/merge_requests/_form.html.haml b/app/views/merge_requests/_form.html.haml index d5271ed0..96692c0f 100644 --- a/app/views/merge_requests/_form.html.haml +++ b/app/views/merge_requests/_form.html.haml @@ -16,7 +16,7 @@ .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") + = f.select(:source_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span3'}) .mr_source_commit .span2 @@ -28,7 +28,7 @@ .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") + = f.select(:target_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span3'}) .mr_target_commit %h4.cdark 2. Fill info @@ -43,7 +43,7 @@ = 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 @@ -56,18 +56,12 @@ = link_to project_merge_request_path(@project, @merge_request), class: "btn cancel-btn" do Cancel - - :javascript $(function(){ disableButtonIfEmptyField("#merge_request_title", ".save-btn"); - $('select#merge_request_assignee_id').chosen(); - $('select#merge_request_source_branch').chosen(); - $('select#merge_request_target_branch').chosen(); 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() }); @@ -79,4 +73,3 @@ $.get("#{branch_to_project_merge_requests_path(@project)}", {ref: $(this).val() }); }); }); - 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/projects/_refs.html.haml b/app/views/projects/_refs.html.haml index 804b8523..dc1f3a28 100644 --- a/app/views/projects/_refs.html.haml +++ b/app/views/projects/_refs.html.haml @@ -1,8 +1,3 @@ = 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" + = select_tag "ref", grouped_options_refs, onchange: "this.form.submit();", class: "project-refs-select chosen" = hidden_field_tag :destination, destination - -:javascript - $(function(){ - $('.project-refs-select').chosen(); - }) diff --git a/app/views/protected_branches/index.html.haml b/app/views/protected_branches/index.html.haml index 33bb448a..43884de1 100644 --- a/app/views/protected_branches/index.html.haml +++ b/app/views/protected_branches/index.html.haml @@ -19,7 +19,7 @@ .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" @@ -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 d51602de..94603f0a 100644 --- a/app/views/refs/_head.html.haml +++ b/app/views/refs/_head.html.haml @@ -1,7 +1,7 @@ %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" + = select_tag "ref", grouped_options_refs, onchange: "$(this.form).trigger('submit');", class: "project-refs-select chosen" = hidden_field_tag :destination, "tree" = hidden_field_tag :path, params[:path] %li{class: "#{'active' if (controller.controller_name == "refs") }"} diff --git a/app/views/refs/_tree.html.haml b/app/views/refs/_tree.html.haml index 297a3b5f..83e73280 100644 --- a/app/views/refs/_tree.html.haml +++ b/app/views/refs/_tree.html.haml @@ -47,10 +47,7 @@ :javascript $(function(){ - $('.project-refs-select').chosen(); - history.pushState({ path: this.path }, '', "#{@history_path}"); - }); // Load last commit log for each file in tree 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/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/team_members/_form.html.haml b/app/views/team_members/_form.html.haml index 192f2735..3736bfea 100644 --- a/app/views/team_members/_form.html.haml +++ b/app/views/team_members/_form.html.haml @@ -10,21 +10,14 @@ %h6 1. Choose people you want in the team .clearfix - = f.label :user_ids, "Peolpe" - .input= select_tag(:user_ids, options_from_collection_for_select(User.not_in_project(@project).all, :id, :name), { class: "xxlarge", multiple: true }) - + = 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= select_tag :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 save-btn" = link_to "Cancel", team_project_path(@project), class: "btn cancel-btn" - - -:javascript - $('select#user_ids').chosen(); - $('select#project_access').chosen(); From e7f483f9f4dffbd675b7fc41b5c2cfd8c7309e0d Mon Sep 17 00:00:00 2001 From: Cyril Date: Mon, 10 Sep 2012 10:50:07 +0200 Subject: [PATCH 016/123] fix typo --- lib/gitlab/backend/gitolite_config.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gitlab/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb index 60eef8e8..0d636d2d 100644 --- a/lib/gitlab/backend/gitolite_config.rb +++ b/lib/gitlab/backend/gitolite_config.rb @@ -148,7 +148,7 @@ module Gitlab # Enable access to all repos for gitolite admin. # We use it for accept merge request feature def admin_all_repo - owner_name = Gitlab.settings.gitolite_admin_key + owner_name = Gitlab.config.gitolite_admin_key # @ALL repos premission for gitolite owner repo_name = "@all" From 52d29f5d5996fd5e5bcd203b5e352afee00f74aa Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 10 Sep 2012 09:13:45 +0300 Subject: [PATCH 017/123] Project team page improved --- app/assets/stylesheets/common.scss | 5 +++-- app/helpers/projects_helper.rb | 4 ++++ app/views/team_members/_show.html.haml | 20 +++++++++++++------- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 012aad03..6f69ba5a 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -181,11 +181,12 @@ span.update-author { } &.joined { - background-color: #1cb9ff; + background-color: #1ca9dd; } &.left { - background-color: #ff5057; + background-color: #888; + float:none; } } diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 34dbb06c..c7dc54ee 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -2,5 +2,9 @@ module ProjectsHelper def grouper_project_members(project) @project.users_projects.sort_by(&:project_access).reverse.group_by(&:project_access) end + + def remove_from_team_message(project, member) + "You are going to remove #{member.user_name} from #{project.name}. Are you sure?" + end end diff --git a/app/views/team_members/_show.html.haml b/app/views/team_members/_show.html.haml index d9a72494..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 + %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 + %td.span5 .right + - if current_user == user + %span.btn.disabled This is you! - if @project.owner == user - %span.btn.disabled.success Project Owner - - if user.blocked + %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" + = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2" From a1ba470e4e0ec5ebbcd47755122878df6d19ad0b Mon Sep 17 00:00:00 2001 From: randx Date: Mon, 10 Sep 2012 09:26:35 +0300 Subject: [PATCH 018/123] Added guard --- Gemfile | 3 +++ Gemfile.lock | 11 +++++++++++ Guardfile | 30 ++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 Guardfile diff --git a/Gemfile b/Gemfile index c8d3821f..d104cbb6 100644 --- a/Gemfile +++ b/Gemfile @@ -109,6 +109,9 @@ group :development, :test do gem "database_cleaner" gem "launchy" gem 'factory_girl_rails' + + gem 'guard-rspec' + gem 'guard-cucumber' end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index 83fd94db..00ece601 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -186,6 +186,14 @@ GEM multi_xml rack rack-mount + guard (1.3.2) + listen (>= 0.4.2) + thor (>= 0.14.6) + guard-cucumber (1.2.0) + cucumber (>= 1.2.0) + guard (>= 1.1.0) + guard-rspec (1.2.1) + guard (>= 1.1) haml (3.1.6) haml-rails (0.3.4) actionpack (~> 3.0) @@ -219,6 +227,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) @@ -403,6 +412,8 @@ DEPENDENCIES grack! grape (~> 0.2.1) grit! + guard-cucumber + guard-rspec haml-rails headless httparty diff --git a/Guardfile b/Guardfile new file mode 100644 index 00000000..ed38f548 --- /dev/null +++ b/Guardfile @@ -0,0 +1,30 @@ +# A sample Guardfile +# More info at https://github.com/guard/guard#readme + +guard 'rspec', :version => 2 do + watch(%r{^spec/.+_spec\.rb$}) + watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{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" } + + # Turnip features and steps + watch(%r{^spec/acceptance/(.+)\.feature$}) + watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' } +end + + +guard 'cucumber' do + watch(%r{^features/.+\.feature$}) + watch(%r{^features/support/.+$}) { 'features' } + watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' } +end From 8795f67f47880f4ac4c88b627c22f1861cda2bc0 Mon Sep 17 00:00:00 2001 From: randx Date: Mon, 10 Sep 2012 09:41:51 +0300 Subject: [PATCH 019/123] REmoved autotest, added notify libs for growl --- Gemfile | 16 ++++++++++++++-- Gemfile.lock | 14 +++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/Gemfile b/Gemfile index d104cbb6..660bef40 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 @@ -102,16 +110,20 @@ group :development, :test do 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-cucumber' + + # Notification + gem 'rb-fsevent', :require => darwin_only('growl') + gem 'growl', :require => darwin_only('growl') + gem 'rb-inotify', :require => linux_only('rb-fsevent') end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index 00ece601..94b16281 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,10 +99,6 @@ 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) @@ -186,6 +181,7 @@ GEM multi_xml rack rack-mount + growl (1.0.3) guard (1.3.2) listen (>= 0.4.2) thor (>= 0.14.6) @@ -283,6 +279,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) @@ -386,8 +385,6 @@ PLATFORMS DEPENDENCIES acts-as-taggable-on (= 2.3.1) annotate! - autotest - autotest-rails awesome_print bootstrap-sass (= 2.0.4) capybara @@ -412,6 +409,7 @@ DEPENDENCIES grack! grape (~> 0.2.1) grit! + growl guard-cucumber guard-rspec haml-rails @@ -431,6 +429,8 @@ DEPENDENCIES 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 From a839cb427cc158330297fd89fbf40321d41349a4 Mon Sep 17 00:00:00 2001 From: randx Date: Mon, 10 Sep 2012 09:43:30 +0300 Subject: [PATCH 020/123] Fix require calls in gemfile --- Gemfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 660bef40..6205594a 100644 --- a/Gemfile +++ b/Gemfile @@ -121,9 +121,9 @@ group :development, :test do gem 'guard-cucumber' # Notification - gem 'rb-fsevent', :require => darwin_only('growl') + gem 'rb-fsevent', :require => darwin_only('rb-fsevent') gem 'growl', :require => darwin_only('growl') - gem 'rb-inotify', :require => linux_only('rb-fsevent') + gem 'rb-inotify', :require => linux_only('rb-inotify') end group :test do From 915dac0055cd801c080ebcd37749f4fc6d2d12c4 Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Mon, 10 Sep 2012 10:41:46 +0300 Subject: [PATCH 021/123] Error throwing moved to api_helper --- lib/api/helpers.rb | 27 ++++++++++++++++++++++++--- lib/api/issues.rb | 6 +++--- lib/api/milestones.rb | 4 ++-- lib/api/projects.rb | 10 +++++----- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index c0ba8747..3a385f15 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -8,7 +8,7 @@ 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 @@ -19,15 +19,36 @@ module Gitlab 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) - error!({'message' => '403 Forbidden'}, 403) + forbidden! end end + # error helpers + + def forbidden! + error!({'message' => '403 Forbidden'}, 403) + end + + def not_found!(resource = nil) + message = ["404"] + message << resource if resource + message << "Not Found" + error!({'message' => message.join(' ')}, 404) + end + + def unauthorized! + error!({'message' => '401 Unauthorized'}, 401) + end + + def not_allowed! + error!({'message' => 'method not allowed'}, 405) + end + private def abilities diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 4cfa7500..659f065e 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -60,7 +60,7 @@ module Gitlab if @issue.save present @issue, with: Entities::Issue else - error!({'message' => '404 Not found'}, 404) + not_found! end end @@ -93,7 +93,7 @@ module Gitlab if @issue.update_attributes(parameters) present @issue, with: Entities::Issue else - error!({'message' => '404 Not found'}, 404) + not_found! end end @@ -105,7 +105,7 @@ module Gitlab # Example Request: # DELETE /projects/:id/issues/:issue_id delete ":id/issues/:issue_id" do - error!({'message' => 'method not allowed'}, 405) + not_allowed! end end end diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index 7c684667..4b0424ba 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -45,7 +45,7 @@ module Gitlab if @milestone.save present @milestone, with: Entities::Milestone else - error!({'message' => '404 Not found'}, 404) + not_found! end end @@ -74,7 +74,7 @@ module Gitlab if @milestone.update_attributes(parameters) present @milestone, with: Entities::Milestone else - error!({'message' => '404 Not found'}, 404) + not_found! end end end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 05b07e8d..9d33323e 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -50,7 +50,7 @@ module Gitlab if @project.saved? present @project, with: Entities::Project else - error!({'message' => '404 Not found'}, 404) + not_found! end end @@ -172,7 +172,7 @@ module Gitlab if @snippet.save present @snippet, with: Entities::ProjectSnippet else - error!({'message' => '404 Not found'}, 404) + not_found! end end @@ -201,7 +201,7 @@ module Gitlab if @snippet.update_attributes(parameters) present @snippet, with: Entities::ProjectSnippet else - error!({'message' => '404 Not found'}, 404) + not_found! end end @@ -244,10 +244,10 @@ module Gitlab 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) From decb3abf18314877c7f4fe9241d46936ebe53205 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Mon, 10 Sep 2012 00:42:36 -0700 Subject: [PATCH 022/123] install spinach-rails --- Gemfile | 1 + Gemfile.lock | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/Gemfile b/Gemfile index 6205594a..4e957e92 100644 --- a/Gemfile +++ b/Gemfile @@ -106,6 +106,7 @@ group :development do end group :development, :test do + gem 'spinach-rails' gem "rspec-rails" gem "capybara" gem "capybara-webkit" diff --git a/Gemfile.lock b/Gemfile.lock index 94b16281..317ff694 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -132,6 +132,7 @@ 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) @@ -172,6 +173,7 @@ GEM thor (>= 0.13.6) gherkin (2.11.0) json (>= 1.4.6) + gherkin-ruby (0.2.1) git (1.2.5) github-markup (0.7.4) gitlab_meta (2.9) @@ -344,6 +346,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) @@ -442,6 +451,7 @@ DEPENDENCIES shoulda-matchers simplecov six + spinach-rails sqlite3 stamp therubyracer From 9f25657ad9b48dab20188bfa51aacbe2e83689e5 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Mon, 10 Sep 2012 00:52:43 -0700 Subject: [PATCH 023/123] modify env file for spinach --- features/support/env.rb | 64 +++++------------------------------------ 1 file changed, 7 insertions(+), 57 deletions(-) diff --git a/features/support/env.rb b/features/support/env.rb index 53578152..aa2f2958 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -1,59 +1,9 @@ -unless ENV['CI'] - require 'simplecov' - SimpleCov.start 'rails' -end +ENV['RAILS_ENV'] = 'test' +require './config/environment' -require 'cucumber/rails' -require 'webmock/cucumber' +require 'rspec' +require 'database_cleaner' -WebMock.allow_net_connect! - -require Rails.root.join 'spec/support/gitolite_stub' -require Rails.root.join 'spec/support/stubbed_repository' -require Rails.root.join 'spec/support/login_helpers' -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 - -# 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." -end - -Cucumber::Rails::Database.javascript_strategy = :truncation - -require 'headless' - -headless = Headless.new -headless.start - -require 'cucumber/rspec/doubles' - -include GitoliteStub - -Before do - stub_gitolite! -end - -World(FactoryGirl::Syntax::Methods) +DatabaseCleaner.strategy = :transaction +Spinach.hooks.before_scenario { DatabaseCleaner.start } +Spinach.hooks.after_scenario { DatabaseCleaner.clean } From bb75052a904c24d1484fa6ec0ad96839effb8ee3 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Mon, 10 Sep 2012 00:53:15 -0700 Subject: [PATCH 024/123] get rid of cucumber step definitions --- features/step_definitions/common_steps.rb | 21 --- features/step_definitions/dashboard_steps.rb | 136 ------------------ .../profile/profile_keys_steps.rb | 34 ----- .../step_definitions/profile/profile_steps.rb | 39 ----- .../project/browse_code_steps.rb | 38 ----- .../project/project_commits_steps.rb | 64 --------- .../project/project_issues_steps.rb | 81 ----------- .../project/project_merge_requests_steps.rb | 38 ----- .../project/project_milestones_steps.rb | 33 ----- .../project/project_team_steps.rb | 55 ------- .../project/project_wiki_steps.rb | 14 -- .../project/projects_steps.rb | 77 ---------- features/step_definitions/visit_steps.rb | 91 ------------ 13 files changed, 721 deletions(-) delete mode 100644 features/step_definitions/common_steps.rb delete mode 100644 features/step_definitions/dashboard_steps.rb delete mode 100644 features/step_definitions/profile/profile_keys_steps.rb delete mode 100644 features/step_definitions/profile/profile_steps.rb delete mode 100644 features/step_definitions/project/browse_code_steps.rb delete mode 100644 features/step_definitions/project/project_commits_steps.rb delete mode 100644 features/step_definitions/project/project_issues_steps.rb delete mode 100644 features/step_definitions/project/project_merge_requests_steps.rb delete mode 100644 features/step_definitions/project/project_milestones_steps.rb delete mode 100644 features/step_definitions/project/project_team_steps.rb delete mode 100644 features/step_definitions/project/project_wiki_steps.rb delete mode 100644 features/step_definitions/project/projects_steps.rb delete mode 100644 features/step_definitions/visit_steps.rb diff --git a/features/step_definitions/common_steps.rb b/features/step_definitions/common_steps.rb deleted file mode 100644 index e9023f92..00000000 --- a/features/step_definitions/common_steps.rb +++ /dev/null @@ -1,21 +0,0 @@ -include LoginHelpers - -Given /^I signin as a user$/ do - login_as :user -end - -When /^I click link "(.*?)"$/ do |link| - click_link link -end - -When /^I click button "(.*?)"$/ do |button| - click_button button -end - -When /^I fill in "(.*?)" with "(.*?)"$/ do |field, value| - fill_in field, :with => value -end - -Given /^show me page$/ do - save_and_open_page -end diff --git a/features/step_definitions/dashboard_steps.rb b/features/step_definitions/dashboard_steps.rb deleted file mode 100644 index 3ddc68e9..00000000 --- a/features/step_definitions/dashboard_steps.rb +++ /dev/null @@ -1,136 +0,0 @@ -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 - -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 - -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 - - 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 - -Given /^user with name "(.*?)" joined project "(.*?)"$/ do |user_name, project_name| - user = Factory.create(:user, {name: user_name}) - project = Project.find_by_name project_name - Event.create( - project: project, - author_id: user.id, - action: Event::Joined - ) -end - -Given /^user with name "(.*?)" left project "(.*?)"$/ do |user_name, project_name| - user = User.find_by_name user_name - project = Project.find_by_name project_name - Event.create( - project: project, - author_id: user.id, - action: Event::Left - ) -end - -Then /^I should see "(.*?)" event$/ do |event_text| - page.should have_content(event_text) -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 25926c53..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 => "ssh-rsa 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 525d43f5..00000000 --- a/features/step_definitions/profile/profile_steps.rb +++ /dev/null @@ -1,39 +0,0 @@ -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 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 - -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 d2ed9a0a..00000000 --- a/features/step_definitions/project/browse_code_steps.rb +++ /dev/null @@ -1,38 +0,0 @@ -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 "(.*?)"$/ 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 - -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 7f20ade4..00000000 --- a/features/step_definitions/project/project_commits_steps.rb +++ /dev/null @@ -1,64 +0,0 @@ -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 - -Then /^I see commit info$/ do - page.should have_content ValidCommit::MESSAGE - page.should have_content "Showing 1 changed file" -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 - -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 d78da53c..00000000 --- a/features/step_definitions/project/project_issues_steps.rb +++ /dev/null @@ -1,81 +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 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 submit new issue "(.*?)"$/ do |arg1| - fill_in "issue_title", with: arg1 - click_button "Submit new issue" -end - -Given /^project "(.*?)" have issues tags:$/ do |arg1, table| - project = Project.find_by_name(arg1) - table.hashes.each do |hash| - Factory :issue, - project: project, - label_list: [hash[:name]] - end -end - -Given /^I visit project "(.*?)" labels page$/ do |arg1| - visit project_labels_path(Project.find_by_name(arg1)) -end - -Then /^I should see label "(.*?)"$/ do |arg1| - within ".labels-table" do - page.should have_content arg1 - end -end - -Given /^I fill in issue search with "(.*?)"$/ do |arg1| - # Because fill_in, with: "" triggers nothing - # we need to trigger a keyup event - if arg1 == '' - page.execute_script("$('.issue_search').val('').keyup();"); - end - fill_in 'issue_search', with: arg1 -end - -When /^I select milestone "(.*?)"$/ do |milestone_title| - select milestone_title, from: "milestone_id" -end - -Then /^I should see selected milestone with title "(.*?)"$/ do |milestone_title| - issues_milestone_selector = "#issue_milestone_id_chzn/a" - wait_until{ page.has_content?("Details") } - page.find(issues_milestone_selector).should have_content(milestone_title) -end - -When /^I select first assignee from "(.*?)" project$/ do |project_name| - project = Project.find_by_name project_name - first_assignee = project.users.first - select first_assignee.name, from: "assignee_id" -end - -Then /^I should see first assignee from "(.*?)" as selected assignee$/ do |project_name| - issues_assignee_selector = "#issue_assignee_id_chzn/a" - wait_until{ page.has_content?("Details") } - project = Project.find_by_name project_name - assignee_name = project.users.first.name - page.find(issues_assignee_selector).should have_content(assignee_name) -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 fddb18ad..00000000 --- a/features/step_definitions/project/project_merge_requests_steps.rb +++ /dev/null @@ -1,38 +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 - -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 - -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 936c52df..00000000 --- a/features/step_definitions/project/project_milestones_steps.rb +++ /dev/null @@ -1,33 +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 - -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 91885e46..00000000 --- a/features/step_definitions/project/project_team_steps.rb +++ /dev/null @@ -1,55 +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 - -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 select "(.*?)" as "(.*?)"$/ do |arg1, arg2| - user = User.find_by_name(arg1) - within "#new_team_member" do - select user.name, :from => "user_ids" - select arg2, :from => "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 31fc050a..00000000 --- a/features/step_definitions/project/project_wiki_steps.rb +++ /dev/null @@ -1,14 +0,0 @@ -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 d22b805f..00000000 --- a/features/step_definitions/project/projects_steps.rb +++ /dev/null @@ -1,77 +0,0 @@ -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 /^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/step_definitions/visit_steps.rb b/features/step_definitions/visit_steps.rb deleted file mode 100644 index 35fc6d44..00000000 --- a/features/step_definitions/visit_steps.rb +++ /dev/null @@ -1,91 +0,0 @@ -Given /^I visit project "(.*?)" issues page$/ do |arg1| - visit project_issues_path(Project.find_by_name(arg1)) -end - -Given /^I visit issue page "(.*?)"$/ do |arg1| - issue = Issue.find_by_title(arg1) - visit project_issue_path(issue.project, issue) -end - -Given /^I visit project "(.*?)" merge requests page$/ do |arg1| - visit project_merge_requests_path(Project.find_by_name(arg1)) -end - -Given /^I visit merge request page "(.*?)"$/ do |arg1| - mr = MergeRequest.find_by_title(arg1) - visit project_merge_request_path(mr.project, mr) -end - -Given /^I visit project "(.*?)" milestones page$/ do |arg1| - @project = Project.find_by_name(arg1) - visit project_milestones_path(@project) -end - -Given /^I visit project commits page$/ do - visit project_commits_path(@project) -end - -Given /^I visit compare refs page$/ do - visit compare_project_commits_path(@project) -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 - -Given /^I click on commit link$/ do - visit project_commit_path(@project, ValidCommit::ID) -end - -Given /^I visit project source page$/ do - visit tree_project_ref_path(@project, @project.root_ref) -end - -Given /^I visit project source page for "(.*?)"$/ do |arg1| - visit tree_project_ref_path(@project, arg1) -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 "(.*?)" team page$/ do |arg1| - visit team_project_path(Project.find_by_name(arg1)) -end - -Given /^I visit project wiki page$/ do - visit project_wiki_path(@project, :index) -end - -Given /^I visit profile page$/ do - visit profile_path -end - -Given /^I visit profile token page$/ do - visit profile_token_path -end - -Given /^I visit profile password page$/ do - visit profile_password_path -end - -Given /^I visit dashboard page$/ do - visit dashboard_path -end - -Given /^I visit dashboard issues page$/ do - visit dashboard_issues_path -end - -Given /^I visit dashboard merge requests page$/ do - visit dashboard_merge_requests_path -end - From d74f54736b8aabb3885648c44d7e253209b8e9e1 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Mon, 10 Sep 2012 01:51:02 -0700 Subject: [PATCH 025/123] rewrite dashboard feature steps using spinach --- features/dashboard/dashboard.feature | 7 +- features/dashboard/issues.feature | 6 +- features/dashboard/merge_requests.feature | 8 +- features/dashboard/search.feature | 10 +-- features/steps/dashboard.rb | 97 ++++++++++++++++++++++ features/steps/dashboard_issues.rb | 32 +++++++ features/steps/dashboard_merge_requests.rb | 33 ++++++++ features/steps/dashboard_search.rb | 23 +++++ features/support/env.rb | 6 ++ 9 files changed, 205 insertions(+), 17 deletions(-) create mode 100644 features/steps/dashboard.rb create mode 100644 features/steps/dashboard_issues.rb create mode 100644 features/steps/dashboard_merge_requests.rb create mode 100644 features/steps/dashboard_search.rb diff --git a/features/dashboard/dashboard.feature b/features/dashboard/dashboard.feature index 98bb4980..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 @@ -25,4 +25,3 @@ Feature: Dashboard 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/steps/dashboard.rb b/features/steps/dashboard.rb new file mode 100644 index 00000000..e69686b3 --- /dev/null +++ b/features/steps/dashboard.rb @@ -0,0 +1,97 @@ +class Dashboard < Spinach::FeatureSteps + 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 + + When 'I visit dashboard page' do + visit dashboard_path + 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 + + Given 'I sign in as a user' do + login_as :user + 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_issues.rb b/features/steps/dashboard_issues.rb new file mode 100644 index 00000000..8704d2ef --- /dev/null +++ b/features/steps/dashboard_issues.rb @@ -0,0 +1,32 @@ +class DashboardIssues < Spinach::FeatureSteps + 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 sign in as a user' do + login_as :user + end + + And '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 + + And 'I visit dashboard issues page' do + visit dashboard_issues_path + end +end diff --git a/features/steps/dashboard_merge_requests.rb b/features/steps/dashboard_merge_requests.rb new file mode 100644 index 00000000..3e057ef9 --- /dev/null +++ b/features/steps/dashboard_merge_requests.rb @@ -0,0 +1,33 @@ +class DashboardMergeRequests < Spinach::FeatureSteps + 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 sign in as a user' do + login_as :user + 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 + + And 'I visit dashboard merge requests page' do + visit dashboard_merge_requests_path + end +end diff --git a/features/steps/dashboard_search.rb b/features/steps/dashboard_search.rb new file mode 100644 index 00000000..122774fc --- /dev/null +++ b/features/steps/dashboard_search.rb @@ -0,0 +1,23 @@ +class DashboardSearch < Spinach::FeatureSteps + 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 + + Given 'I sign in as a user' do + login_as :user + end + + And 'I own project "Shop"' do + @project = Factory :project, :name => "Shop" + @project.add_access(@user, :admin) + end + + And 'I visit dashboard search page' do + visit search_path + end +end diff --git a/features/support/env.rb b/features/support/env.rb index aa2f2958..2900e1cb 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -4,6 +4,12 @@ require './config/environment' require 'rspec' require 'database_cleaner' +%w(login_helpers stubbed_repository).each do |f| + require Rails.root.join('spec', 'support', f) +end + +include LoginHelpers + DatabaseCleaner.strategy = :transaction Spinach.hooks.before_scenario { DatabaseCleaner.start } Spinach.hooks.after_scenario { DatabaseCleaner.clean } From 7aeb92b8e4bb279346d9dcec7bbca1725cec8eb1 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Mon, 10 Sep 2012 02:40:51 -0700 Subject: [PATCH 026/123] rewrite profile feature steps using spinach --- features/profile/profile.feature | 4 +-- features/profile/ssh_keys.feature | 13 +++---- features/steps/profile.rb | 57 ++++++++++++++++++++++++++++++ features/steps/profile_ssh_keys.rb | 50 ++++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 10 deletions(-) create mode 100644 features/steps/profile.rb create mode 100644 features/steps/profile_ssh_keys.rb diff --git a/features/profile/profile.feature b/features/profile/profile.feature index afda4b55..f4b2f198 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 diff --git a/features/profile/ssh_keys.feature b/features/profile/ssh_keys.feature index c81503ed..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 | - | ssh-rsa Work | - | ssh-rsa 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/steps/profile.rb b/features/steps/profile.rb new file mode 100644 index 00000000..c7e6be3f --- /dev/null +++ b/features/steps/profile.rb @@ -0,0 +1,57 @@ +class Profile < Spinach::FeatureSteps + 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 + + 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 + + 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 + + And '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 + + And 'I should see new token' do + find("#token").value.should_not == @old_token + find("#token").value.should == @user.reload.private_token + end + + Given 'I sign in as a user' do + login_as :user + end +end diff --git a/features/steps/profile_ssh_keys.rb b/features/steps/profile_ssh_keys.rb new file mode 100644 index 00000000..9360f66f --- /dev/null +++ b/features/steps/profile_ssh_keys.rb @@ -0,0 +1,50 @@ +class ProfileSshKeys < Spinach::FeatureSteps + 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 + + Given 'I sign in as a user' do + login_as :user + end + + And 'I have ssh key "ssh-rsa Work"' do + Factory :key, :user => @user, :title => "ssh-rsa Work", :key => "jfKLJDFKSFJSHFJssh-rsa Work" + end +end From a065557208d6076ec869144346e06c7de714389c Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Mon, 10 Sep 2012 13:49:00 +0300 Subject: [PATCH 027/123] Common errors method added --- lib/api/helpers.rb | 12 ++++++++---- spec/requests/api/projects_spec.rb | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 3a385f15..054eb2d3 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -31,22 +31,26 @@ module Gitlab # error helpers def forbidden! - error!({'message' => '403 Forbidden'}, 403) + render_api_error!('403 Forbidden', 403) end def not_found!(resource = nil) message = ["404"] message << resource if resource message << "Not Found" - error!({'message' => message.join(' ')}, 404) + render_api_error!(message.join(' '), 404) end def unauthorized! - error!({'message' => '401 Unauthorized'}, 401) + render_api_error!('401 Unauthorized', 401) end def not_allowed! - error!({'message' => 'method not allowed'}, 405) + render_api_error!('Method Not Allowed', 405) + end + + def render_api_error!(message, status) + error!({'message' => message}, status) end private diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 439aecce..9388403f 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -85,7 +85,7 @@ describe Gitlab::API do it "should return a 404 error if not found" do get api("/projects/42", user) response.status.should == 404 - json_response['message'].should == '404 Not found' + json_response['message'].should == '404 Not Found' end end From 080bd12e167dceb3274bb488b7be787379d126b4 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Mon, 10 Sep 2012 04:27:11 -0700 Subject: [PATCH 028/123] rewrite project commits features using spinach --- .../commits/branches.feature | 15 +++-- .../commits/commit_comments.feature | 6 +- .../commits/commits.feature | 9 ++- .../commits/tags.feature | 9 +-- .../create_project.feature | 0 .../{projects => project}/deploy_keys.feature | 0 .../issues/issues.feature | 0 .../issues/labels.feature | 0 .../issues/milestones.feature | 0 .../merge_requests.feature | 0 .../{projects => project}/network.feature | 0 .../{projects => project}/project.feature | 0 .../{projects => project}/snippets.feature | 0 .../source/browse_files.feature | 0 .../source/git_blame.feature | 0 .../team_management.feature | 0 features/{projects => project}/wall.feature | 0 .../{projects => project}/web_hooks.feature | 0 features/{projects => project}/wiki.feature | 0 features/steps/project_browse_branches.rb | 44 ++++++++++++++ features/steps/project_browse_commits.rb | 60 +++++++++++++++++++ features/steps/project_browse_tags.rb | 19 ++++++ features/steps/project_comment_commit.rb | 23 +++++++ features/support/env.rb | 13 +++- 24 files changed, 178 insertions(+), 20 deletions(-) rename features/{projects => project}/commits/branches.feature (66%) rename features/{projects => project}/commits/commit_comments.feature (72%) rename features/{projects => project}/commits/commits.feature (82%) rename features/{projects => project}/commits/tags.feature (53%) rename features/{projects => project}/create_project.feature (100%) rename features/{projects => project}/deploy_keys.feature (100%) rename features/{projects => project}/issues/issues.feature (100%) rename features/{projects => project}/issues/labels.feature (100%) rename features/{projects => project}/issues/milestones.feature (100%) rename features/{projects => project}/merge_requests.feature (100%) rename features/{projects => project}/network.feature (100%) rename features/{projects => project}/project.feature (100%) rename features/{projects => project}/snippets.feature (100%) rename features/{projects => project}/source/browse_files.feature (100%) rename features/{projects => project}/source/git_blame.feature (100%) rename features/{projects => project}/team_management.feature (100%) rename features/{projects => project}/wall.feature (100%) rename features/{projects => project}/web_hooks.feature (100%) rename features/{projects => project}/wiki.feature (100%) create mode 100644 features/steps/project_browse_branches.rb create mode 100644 features/steps/project_browse_commits.rb create mode 100644 features/steps/project_browse_tags.rb create mode 100644 features/steps/project_comment_commit.rb 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 100% rename from features/projects/create_project.feature rename to features/project/create_project.feature diff --git a/features/projects/deploy_keys.feature b/features/project/deploy_keys.feature similarity index 100% rename from features/projects/deploy_keys.feature rename to features/project/deploy_keys.feature diff --git a/features/projects/issues/issues.feature b/features/project/issues/issues.feature similarity index 100% rename from features/projects/issues/issues.feature rename to features/project/issues/issues.feature diff --git a/features/projects/issues/labels.feature b/features/project/issues/labels.feature similarity index 100% rename from features/projects/issues/labels.feature rename to features/project/issues/labels.feature diff --git a/features/projects/issues/milestones.feature b/features/project/issues/milestones.feature similarity index 100% rename from features/projects/issues/milestones.feature rename to features/project/issues/milestones.feature diff --git a/features/projects/merge_requests.feature b/features/project/merge_requests.feature similarity index 100% rename from features/projects/merge_requests.feature rename to features/project/merge_requests.feature diff --git a/features/projects/network.feature b/features/project/network.feature similarity index 100% rename from features/projects/network.feature rename to features/project/network.feature diff --git a/features/projects/project.feature b/features/project/project.feature similarity index 100% rename from features/projects/project.feature rename to features/project/project.feature diff --git a/features/projects/snippets.feature b/features/project/snippets.feature similarity index 100% rename from features/projects/snippets.feature rename to features/project/snippets.feature diff --git a/features/projects/source/browse_files.feature b/features/project/source/browse_files.feature similarity index 100% rename from features/projects/source/browse_files.feature rename to features/project/source/browse_files.feature diff --git a/features/projects/source/git_blame.feature b/features/project/source/git_blame.feature similarity index 100% rename from features/projects/source/git_blame.feature rename to features/project/source/git_blame.feature diff --git a/features/projects/team_management.feature b/features/project/team_management.feature similarity index 100% rename from features/projects/team_management.feature rename to features/project/team_management.feature diff --git a/features/projects/wall.feature b/features/project/wall.feature similarity index 100% rename from features/projects/wall.feature rename to features/project/wall.feature diff --git a/features/projects/web_hooks.feature b/features/project/web_hooks.feature similarity index 100% rename from features/projects/web_hooks.feature rename to features/project/web_hooks.feature diff --git a/features/projects/wiki.feature b/features/project/wiki.feature similarity index 100% rename from features/projects/wiki.feature rename to features/project/wiki.feature diff --git a/features/steps/project_browse_branches.rb b/features/steps/project_browse_branches.rb new file mode 100644 index 00000000..9fb2e59d --- /dev/null +++ b/features/steps/project_browse_branches.rb @@ -0,0 +1,44 @@ +class ProjectBrowseBranches < Spinach::FeatureSteps + 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 + + Given 'I sign in as a user' do + login_as :user + end + + And 'I own project "Shop"' do + @project = Factory :project, :name => "Shop" + @project.add_access(@user, :admin) + end + + And 'project "Shop" has protected branches' do + project = Project.find_by_name("Shop") + project.protected_branches.create(:name => "stable") + end + + Given 'I visit project branches page' do + visit branches_project_repository_path(@project) + end +end diff --git a/features/steps/project_browse_commits.rb b/features/steps/project_browse_commits.rb new file mode 100644 index 00000000..71c592a7 --- /dev/null +++ b/features/steps/project_browse_commits.rb @@ -0,0 +1,60 @@ +class ProjectBrowseCommits < Spinach::FeatureSteps + 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 + + 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 + + Given 'I sign in as a user' do + login_as :user + end + + And 'I own project "Shop"' do + @project = Factory :project, :name => "Shop" + @project.add_access(@user, :admin) + end + + Given 'I visit project commits page' do + visit project_commits_path(@project) + end +end diff --git a/features/steps/project_browse_tags.rb b/features/steps/project_browse_tags.rb new file mode 100644 index 00000000..c6bea691 --- /dev/null +++ b/features/steps/project_browse_tags.rb @@ -0,0 +1,19 @@ +class ProjectBrowseTags < Spinach::FeatureSteps + Then 'I should see "Shop" all tags list' do + page.should have_content "Tags" + page.should have_content "v1.2.1" + end + + Given 'I sign in as a user' do + login_as :user + end + + And 'I own project "Shop"' do + @project = Factory :project, :name => "Shop" + @project.add_access(@user, :admin) + end + + Given 'I visit project tags page' do + visit tags_project_repository_path(@project) + end +end diff --git a/features/steps/project_comment_commit.rb b/features/steps/project_comment_commit.rb new file mode 100644 index 00000000..04e94c7d --- /dev/null +++ b/features/steps/project_comment_commit.rb @@ -0,0 +1,23 @@ +class ProjectCommentCommit < Spinach::FeatureSteps + 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 sign in as a user' do + login_as :user + end + + And 'I own project "Shop"' do + @project = Factory :project, :name => "Shop" + @project.add_access(@user, :admin) + end + + Given 'I visit project commit page' do + visit project_commit_path(@project, ValidCommit::ID) + end +end diff --git a/features/support/env.rb b/features/support/env.rb index 2900e1cb..38d828a2 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -4,12 +4,21 @@ require './config/environment' require 'rspec' require 'database_cleaner' -%w(login_helpers stubbed_repository).each do |f| +%w(gitolite_stub login_helpers stubbed_repository valid_commit).each do |f| require Rails.root.join('spec', 'support', f) end include LoginHelpers +include GitoliteStub -DatabaseCleaner.strategy = :transaction +WebMock.allow_net_connect! + +DatabaseCleaner.strategy = :truncation Spinach.hooks.before_scenario { DatabaseCleaner.start } Spinach.hooks.after_scenario { DatabaseCleaner.clean } + +Spinach.hooks.before_run do + RSpec::Mocks::setup self + + stub_gitolite! +end From a3d22297dcd7b547412cf0284a27ef11f90c20ad Mon Sep 17 00:00:00 2001 From: Minoru NAKATA Date: Mon, 10 Sep 2012 20:35:09 +0900 Subject: [PATCH 029/123] fix haml template error for ldap login. --- app/views/devise/sessions/_new_ldap.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/devise/sessions/_new_ldap.html.haml b/app/views/devise/sessions/_new_ldap.html.haml index 85010df7..4233aa61 100644 --- a/app/views/devise/sessions/_new_ldap.html.haml +++ b/app/views/devise/sessions/_new_ldap.html.haml @@ -15,7 +15,7 @@ $(function() { $('#new_user').toggle(); }); - = form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { :class => "login-box" }) do |f| += form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { :class => "login-box" }) do |f| = f.text_field :email, :class => "text top", :placeholder => "Email" = f.password_field :password, :class => "text bottom", :placeholder => "Password" - if devise_mapping.rememberable? From 698500dd786cc931cabeb0f44087c0cd11bd0131 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Mon, 10 Sep 2012 05:34:01 -0700 Subject: [PATCH 030/123] add spinach steps for project issues and source features --- features/project/issues/issues.feature | 5 +- features/project/issues/labels.feature | 11 +- features/project/issues/milestones.feature | 6 +- features/project/source/browse_files.feature | 14 +- features/project/source/git_blame.feature | 10 +- features/steps/project_browse_files.rb | 51 ++++++ features/steps/project_browse_git_repo.rb | 28 ++++ features/steps/project_issues.rb | 160 +++++++++++++++++++ features/steps/project_labels.rb | 33 ++++ features/steps/project_milestones.rb | 51 ++++++ features/support/env.rb | 2 + 11 files changed, 345 insertions(+), 26 deletions(-) create mode 100644 features/steps/project_browse_files.rb create mode 100644 features/steps/project_browse_git_repo.rb create mode 100644 features/steps/project_issues.rb create mode 100644 features/steps/project_labels.rb create mode 100644 features/steps/project_milestones.rb diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature index b2301b3f..596e8bd7 100644 --- a/features/project/issues/issues.feature +++ b/features/project/issues/issues.feature @@ -1,6 +1,6 @@ -Feature: Issues +Feature: Project Issues Background: - Given I signin as a user + 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 @@ -79,4 +79,3 @@ Feature: Issues 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 index 5a20bfd6..e601a41b 100644 --- a/features/project/issues/labels.feature +++ b/features/project/issues/labels.feature @@ -1,12 +1,9 @@ -Feature: Labels +Feature: Project Labels Background: - Given I signin as a user + Given I sign in as a user And I own project "Shop" - And project "Shop" have issues tags: - | name | - | bug | - | feature | - Given I visit project "Shop" labels page + 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" diff --git a/features/project/issues/milestones.feature b/features/project/issues/milestones.feature index d78096a4..a57f67d6 100644 --- a/features/project/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/project/source/browse_files.feature b/features/project/source/browse_files.feature index 04aebc19..b12b0ee3 100644 --- a/features/project/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 index 6aa6be47..93ed20a8 100644 --- a/features/project/source/git_blame.feature +++ b/features/project/source/git_blame.feature @@ -1,10 +1,10 @@ -Feature: Browse git repo - Background: - Given I signin as a user +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 file from repo + Given I click on "Gemfile" file in repo And I click blame button - Then I should see git file blame + Then I should see git file blame diff --git a/features/steps/project_browse_files.rb b/features/steps/project_browse_files.rb new file mode 100644 index 00000000..ad320584 --- /dev/null +++ b/features/steps/project_browse_files.rb @@ -0,0 +1,51 @@ +class ProjectBrowseFiles < Spinach::FeatureSteps + 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 "8470d70"' do + visit tree_project_ref_path(@project, "8470d70") + 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 + + Given 'I visit blob file from repo' do + visit tree_project_ref_path(@project, ValidCommit::ID, :path => ValidCommit::BLOB_FILE_PATH) + 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 + + Given 'I sign in as a user' do + login_as :user + end + + And 'I own project "Shop"' do + @project = Factory :project, :name => "Shop" + @project.add_access(@user, :admin) + end + + Given 'I visit project source page' do + visit tree_project_ref_path(@project, @project.root_ref) + end +end diff --git a/features/steps/project_browse_git_repo.rb b/features/steps/project_browse_git_repo.rb new file mode 100644 index 00000000..56b33a90 --- /dev/null +++ b/features/steps/project_browse_git_repo.rb @@ -0,0 +1,28 @@ +class ProjectBrowseGitRepo < Spinach::FeatureSteps + 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 + + Given 'I sign in as a user' do + login_as :user + end + + And 'I own project "Shop"' do + @project = Factory :project, :name => "Shop" + @project.add_access(@user, :admin) + end + + Given 'I visit project source page' do + visit tree_project_ref_path(@project, @project.root_ref) + end +end diff --git a/features/steps/project_issues.rb b/features/steps/project_issues.rb new file mode 100644 index 00000000..c3fca0c6 --- /dev/null +++ b/features/steps/project_issues.rb @@ -0,0 +1,160 @@ +class ProjectIssues < Spinach::FeatureSteps + 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 visit issue page "Release 0.4"' do + issue = Issue.find_by_title("Release 0.4") + visit project_issue_path(issue.project, issue) + end + + And '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 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 do + issue = Factory :issue, :project => project, :milestone => milestone + end + 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 do + issue = Factory :issue, :project => project, :milestone => milestone + end + end + + And 'I visit project "Shop" issues page' do + visit project_issues_path(Project.find_by_name("Shop")) + 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 + + Given 'I sign in as a user' do + login_as :user + end + + And 'I own project "Shop"' do + @project = Factory :project, :name => "Shop" + @project.add_access(@user, :admin) + 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_labels.rb b/features/steps/project_labels.rb new file mode 100644 index 00000000..2e83824f --- /dev/null +++ b/features/steps/project_labels.rb @@ -0,0 +1,33 @@ +class ProjectLabels < Spinach::FeatureSteps + 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 + + Given 'I sign in as a user' do + login_as :user + end + + And 'I own project "Shop"' do + @project = Factory :project, :name => "Shop" + @project.add_access(@user, :admin) + 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 + + Given 'I visit project "Shop" labels page' do + visit project_labels_path(Project.find_by_name("Shop")) + end +end diff --git a/features/steps/project_milestones.rb b/features/steps/project_milestones.rb new file mode 100644 index 00000000..97574d1c --- /dev/null +++ b/features/steps/project_milestones.rb @@ -0,0 +1,51 @@ +class ProjectMilestones < Spinach::FeatureSteps + 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 + + Given 'I sign in as a user' do + login_as :user + end + + And 'I own project "Shop"' do + @project = Factory :project, :name => "Shop" + @project.add_access(@user, :admin) + 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 do + issue = Factory :issue, :project => project, :milestone => milestone + end + end + + Given 'I visit project "Shop" milestones page' do + @project = Project.find_by_name("Shop") + visit project_milestones_path(@project) + end +end diff --git a/features/support/env.rb b/features/support/env.rb index 38d828a2..7bd89801 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -3,6 +3,7 @@ require './config/environment' require 'rspec' require 'database_cleaner' +require 'spinach/capybara' %w(gitolite_stub login_helpers stubbed_repository valid_commit).each do |f| require Rails.root.join('spec', 'support', f) @@ -12,6 +13,7 @@ include LoginHelpers include GitoliteStub WebMock.allow_net_connect! +Capybara.javascript_driver = :webkit DatabaseCleaner.strategy = :truncation Spinach.hooks.before_scenario { DatabaseCleaner.start } From 8d171a8cbcec2748b583b75b2e304634e0ecd348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vanja=20Radovanovi=C4=87?= Date: Mon, 10 Sep 2012 14:40:35 +0200 Subject: [PATCH 031/123] fixed commit title when commit message is an empty string and ensured that link_to_gfm helper doesn't break on nil body --- app/decorators/commit_decorator.rb | 2 +- app/helpers/gitlab_markdown_helper.rb | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/decorators/commit_decorator.rb b/app/decorators/commit_decorator.rb index f813ed25..56067221 100644 --- a/app/decorators/commit_decorator.rb +++ b/app/decorators/commit_decorator.rb @@ -16,7 +16,7 @@ class CommitDecorator < ApplicationDecorator # 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 unless safe_message + return no_commit_message unless safe_message && !safe_message.strip.empty? title_end = safe_message.index(/\n/) if (!title_end && safe_message.length > 80) || (title_end && title_end > 80) diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index e97e46f5..a54d2e3b 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -11,6 +11,8 @@ 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 = {}) + return "" unless body && !body.strip.empty? + gfm_body = gfm(body, html_options) gfm_body.gsub!(%r{.*?}m) do |match| From b58155113b46690d9390597f9f1feccf44b00989 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Mon, 10 Sep 2012 06:35:23 -0700 Subject: [PATCH 032/123] add spinach steps for remaining features --- features/project/deploy_keys.feature | 0 features/project/merge_requests.feature | 6 +- features/project/network.feature | 5 +- features/project/project.feature | 13 +-- features/project/snippets.feature | 0 features/project/team_management.feature | 15 ++-- features/project/wall.feature | 5 +- features/project/web_hooks.feature | 0 features/project/wiki.feature | 6 +- features/steps/create_project.rb | 27 ++++++ features/steps/project.rb | 15 ++++ features/steps/project_merge_requests.rb | 102 ++++++++++++++++++++++ features/steps/project_network_graph.rb | 28 ++++++ features/steps/project_team_management.rb | 98 +++++++++++++++++++++ features/steps/project_wall.rb | 24 +++++ features/steps/project_wiki.rb | 37 ++++++++ 16 files changed, 357 insertions(+), 24 deletions(-) delete mode 100644 features/project/deploy_keys.feature delete mode 100644 features/project/snippets.feature delete mode 100644 features/project/web_hooks.feature create mode 100644 features/steps/create_project.rb create mode 100644 features/steps/project.rb create mode 100644 features/steps/project_merge_requests.rb create mode 100644 features/steps/project_network_graph.rb create mode 100644 features/steps/project_team_management.rb create mode 100644 features/steps/project_wall.rb create mode 100644 features/steps/project_wiki.rb diff --git a/features/project/deploy_keys.feature b/features/project/deploy_keys.feature deleted file mode 100644 index e69de29b..00000000 diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature index 54b6ccde..80f00986 100644 --- a/features/project/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/project/network.feature b/features/project/network.feature index 61c05eb3..31ce5ad3 100644 --- a/features/project/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 index 895a928f..1c9f201d 100644 --- a/features/project/project.feature +++ b/features/project/project.feature @@ -1,11 +1,14 @@ -Feature: Project +Feature: Projects Background: Given I signin as a user And I own project "Shop" - And I visit project "Shop" page + And I visit project "Shop" page - Scenario: I should see project activity + # @wip + # Scenario: I should see project activity - Scenario: I edit project + # @wip + # Scenario: I edit project - Scenario: I visit attachments + # @wip + # Scenario: I visit attachments diff --git a/features/project/snippets.feature b/features/project/snippets.feature deleted file mode 100644 index e69de29b..00000000 diff --git a/features/project/team_management.feature b/features/project/team_management.feature index b5b485e2..ae0c459f 100644 --- a/features/project/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/project/wall.feature b/features/project/wall.feature index ed675e2c..c92dbf82 100644 --- a/features/project/wall.feature +++ b/features/project/wall.feature @@ -7,11 +7,12 @@ Feature: Project Wall Background: Given I signin 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/project/web_hooks.feature b/features/project/web_hooks.feature deleted file mode 100644 index e69de29b..00000000 diff --git a/features/project/wiki.feature b/features/project/wiki.feature index 4441ada2..51370565 100644 --- a/features/project/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/steps/create_project.rb b/features/steps/create_project.rb new file mode 100644 index 00000000..80f6f708 --- /dev/null +++ b/features/steps/create_project.rb @@ -0,0 +1,27 @@ +class CreateProject < Spinach::FeatureSteps + Given 'I signin as a user' do + login_as :user + end + + When 'I visit new project page' do + visit new_project_path + end + + 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.rb b/features/steps/project.rb new file mode 100644 index 00000000..666a65fa --- /dev/null +++ b/features/steps/project.rb @@ -0,0 +1,15 @@ +class Projects < Spinach::FeatureSteps + Given 'I sign in as a user' do + login_as :user + end + + And 'I own project "Shop"' do + @project = Factory :project, :name => "Shop" + @project.add_access(@user, :admin) + end + + And 'I visit project "Shop" page' do + project = Project.find_by_name("Shop") + visit project_path(project) + end +end diff --git a/features/steps/project_merge_requests.rb b/features/steps/project_merge_requests.rb new file mode 100644 index 00000000..8515e7e8 --- /dev/null +++ b/features/steps/project_merge_requests.rb @@ -0,0 +1,102 @@ +class ProjectMergeRequests < Spinach::FeatureSteps + 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 + + 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 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 sign in as a user' do + login_as :user + end + + And 'I own project "Shop"' do + @project = Factory :project, :name => "Shop" + @project.add_access(@user, :admin) + 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 + + And 'I visit project "Shop" merge requests page' do + visit project_merge_requests_path(Project.find_by_name("Shop")) + end +end diff --git a/features/steps/project_network_graph.rb b/features/steps/project_network_graph.rb new file mode 100644 index 00000000..d87f3d82 --- /dev/null +++ b/features/steps/project_network_graph.rb @@ -0,0 +1,28 @@ +class ProjectNetworkGraph < Spinach::FeatureSteps + 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 + + Given 'I sign in as a user' do + login_as :user + end + + And 'I own project "Shop"' do + @project = Factory :project, :name => "Shop" + @project.add_access(@user, :admin) + 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_team_management.rb b/features/steps/project_team_management.rb new file mode 100644 index 00000000..9cee75bd --- /dev/null +++ b/features/steps/project_team_management.rb @@ -0,0 +1,98 @@ +class ProjectTeamManagement < Spinach::FeatureSteps + 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 + + Then 'I visit project "Shop" team page' do + visit team_project_path(Project.find_by_name("Shop")) + 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 + + Given 'I sign in as a user' do + login_as :user + end + + And 'I own project "Shop"' do + @project = Factory :project, :name => "Shop" + @project.add_access(@user, :admin) + 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_wall.rb b/features/steps/project_wall.rb new file mode 100644 index 00000000..b94bd0bb --- /dev/null +++ b/features/steps/project_wall.rb @@ -0,0 +1,24 @@ +class ProjectWall < Spinach::FeatureSteps + 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 + + Then 'I visit project "Shop" wall page' do + project = Project.find_by_name("Shop") + visit wall_project_path(project) + end + + Given 'I signin as a user' do + login_as :user + end + + And 'I own project "Shop"' do + @project = Factory :project, :name => "Shop" + @project.add_access(@user, :admin) + end +end diff --git a/features/steps/project_wiki.rb b/features/steps/project_wiki.rb new file mode 100644 index 00000000..8c8c7c8d --- /dev/null +++ b/features/steps/project_wiki.rb @@ -0,0 +1,37 @@ +class ProjectWiki < Spinach::FeatureSteps + 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 + + And '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 sign in as a user' do + login_as :user + end + + And 'I own project "Shop"' do + @project = Factory :project, :name => "Shop" + @project.add_access(@user, :admin) + end + + Given 'I visit project wiki page' do + visit project_wiki_path(@project, :index) + end +end From ae9689f8ffdf8a69bd803021d1f57a37aba06e0d Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Mon, 10 Sep 2012 06:40:57 -0700 Subject: [PATCH 033/123] remove cucumber completely --- Gemfile | 2 -- Gemfile.lock | 16 ---------- config/cucumber.yml | 8 ----- lib/tasks/cucumber.rake | 65 -------------------------------------- lib/tasks/gitlab/test.rake | 5 ++- lib/tasks/travis.rake | 2 +- script/cucumber | 10 ------ 7 files changed, 3 insertions(+), 105 deletions(-) delete mode 100644 config/cucumber.yml delete mode 100644 lib/tasks/cucumber.rake delete mode 100755 script/cucumber diff --git a/Gemfile b/Gemfile index 4e957e92..0609f6fd 100644 --- a/Gemfile +++ b/Gemfile @@ -119,7 +119,6 @@ group :development, :test do # Guard gem 'guard-rspec' - gem 'guard-cucumber' # Notification gem 'rb-fsevent', :require => darwin_only('rb-fsevent') @@ -128,7 +127,6 @@ group :development, :test do end group :test do - gem 'cucumber-rails', :require => false gem "simplecov", :require => false gem "shoulda-matchers" gem 'email_spec' diff --git a/Gemfile.lock b/Gemfile.lock index 317ff694..38094518 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -134,15 +134,6 @@ GEM 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) @@ -171,8 +162,6 @@ GEM 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) github-markup (0.7.4) @@ -187,9 +176,6 @@ GEM guard (1.3.2) listen (>= 0.4.2) thor (>= 0.14.6) - guard-cucumber (1.2.0) - cucumber (>= 1.2.0) - guard (>= 1.1.0) guard-rspec (1.2.1) guard (>= 1.1) haml (3.1.6) @@ -403,7 +389,6 @@ DEPENDENCIES chosen-rails coffee-rails (= 3.2.2) colored - cucumber-rails database_cleaner devise (~> 2.1.0) draper @@ -419,7 +404,6 @@ DEPENDENCIES grape (~> 0.2.1) grit! growl - guard-cucumber guard-rspec haml-rails headless 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/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/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/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/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 From ef4e9c24d3dc870eb194591522dda6ec8dde7192 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Mon, 10 Sep 2012 06:43:49 -0700 Subject: [PATCH 034/123] install guard-spinach --- Gemfile | 1 + Gemfile.lock | 4 ++++ Guardfile | 16 ++++++---------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Gemfile b/Gemfile index 0609f6fd..0a5f730d 100644 --- a/Gemfile +++ b/Gemfile @@ -119,6 +119,7 @@ group :development, :test do # Guard gem 'guard-rspec' + gem 'guard-spinach' # Notification gem 'rb-fsevent', :require => darwin_only('rb-fsevent') diff --git a/Gemfile.lock b/Gemfile.lock index 38094518..8046b92b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -178,6 +178,9 @@ GEM 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) @@ -405,6 +408,7 @@ DEPENDENCIES grit! growl guard-rspec + guard-spinach haml-rails headless httparty diff --git a/Guardfile b/Guardfile index ed38f548..6ed414bc 100644 --- a/Guardfile +++ b/Guardfile @@ -13,18 +13,14 @@ guard 'rspec', :version => 2 do 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" } - - # Turnip features and steps - watch(%r{^spec/acceptance/(.+)\.feature$}) - watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' } end - -guard 'cucumber' do - watch(%r{^features/.+\.feature$}) - watch(%r{^features/support/.+$}) { 'features' } - watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' } +guard 'spinach' do + watch(%r|^features/(.*)\.feature|) + watch(%r|^features/steps/(.*)([^/]+)\.rb|) do |m| + "features/#{m[1]}#{m[2]}.feature" + end end From 6d76e000d07300ab9e8e8c74b90db0abcdc48451 Mon Sep 17 00:00:00 2001 From: miks Date: Mon, 10 Sep 2012 16:50:01 +0300 Subject: [PATCH 035/123] Add authorization to hooks requests --- lib/api/projects.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index dfdd359c..cf23dc5f 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -113,6 +113,7 @@ module Gitlab # 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 @@ -125,6 +126,7 @@ module Gitlab # 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 @@ -141,6 +143,7 @@ module Gitlab # 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 From 7e2846fb57ef24dfac0de57f7b086a7415cc44e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vanja=20Radovanovi=C4=87?= Date: Mon, 10 Sep 2012 17:32:31 +0200 Subject: [PATCH 036/123] using blank?, much shorter --- app/decorators/commit_decorator.rb | 2 +- app/helpers/gitlab_markdown_helper.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/decorators/commit_decorator.rb b/app/decorators/commit_decorator.rb index 56067221..c85f7400 100644 --- a/app/decorators/commit_decorator.rb +++ b/app/decorators/commit_decorator.rb @@ -16,7 +16,7 @@ class CommitDecorator < ApplicationDecorator # 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 unless safe_message && !safe_message.strip.empty? + 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) diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index a54d2e3b..511d4628 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -11,7 +11,7 @@ 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 = {}) - return "" unless body && !body.strip.empty? + return "" if body.blank? gfm_body = gfm(body, html_options) From 79eb5ab396690c613ea6e13c3c941ba1fa80f217 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Mon, 10 Sep 2012 08:35:03 -0700 Subject: [PATCH 037/123] refactor feature steps --- features/project/create_project.feature | 2 +- features/project/wall.feature | 6 +- features/steps/{ => dashboard}/dashboard.rb | 11 +- .../steps/{ => dashboard}/dashboard_issues.rb | 21 +--- .../dashboard_merge_requests.rb | 20 +--- .../steps/{ => dashboard}/dashboard_search.rb | 11 +- features/steps/{ => profile}/profile.rb | 17 +-- .../steps/{ => profile}/profile_ssh_keys.rb | 6 +- features/steps/project.rb | 15 --- .../steps/{ => project}/create_project.rb | 11 +- features/steps/project/project.rb | 5 + .../{ => project}/project_browse_branches.rb | 17 +-- .../{ => project}/project_browse_commits.rb | 21 +--- .../{ => project}/project_browse_files.rb | 25 +--- .../{ => project}/project_browse_git_repo.rb | 17 +-- features/steps/project/project_browse_tags.rb | 10 ++ .../steps/project/project_comment_commit.rb | 6 + .../steps/{ => project}/project_issues.rb | 40 ++----- .../steps/{ => project}/project_labels.rb | 17 +-- .../{ => project}/project_merge_requests.rb | 32 +---- .../steps/{ => project}/project_milestones.rb | 22 +--- .../{ => project}/project_network_graph.rb | 12 +- .../{ => project}/project_team_management.rb | 17 +-- features/steps/project/project_wall.rb | 6 + features/steps/project/project_wiki.rb | 20 ++++ features/steps/project_browse_tags.rb | 19 --- features/steps/project_comment_commit.rb | 23 ---- features/steps/project_wall.rb | 24 ---- features/steps/project_wiki.rb | 37 ------ features/steps/shared/authentication.rb | 10 ++ features/steps/shared/note.rb | 21 ++++ features/steps/shared/paths.rb | 112 ++++++++++++++++++ features/steps/shared/project.rb | 8 ++ features/support/env.rb | 5 +- 34 files changed, 270 insertions(+), 376 deletions(-) rename features/steps/{ => dashboard}/dashboard.rb (95%) rename features/steps/{ => dashboard}/dashboard_issues.rb (52%) rename features/steps/{ => dashboard}/dashboard_merge_requests.rb (58%) rename features/steps/{ => dashboard}/dashboard_search.rb (74%) rename features/steps/{ => profile}/profile.rb (80%) rename features/steps/{ => profile}/profile_ssh_keys.rb (94%) delete mode 100644 features/steps/project.rb rename features/steps/{ => project}/create_project.rb (76%) create mode 100644 features/steps/project/project.rb rename features/steps/{ => project}/project_browse_branches.rb (73%) rename features/steps/{ => project}/project_browse_commits.rb (79%) rename features/steps/{ => project}/project_browse_files.rb (58%) rename features/steps/{ => project}/project_browse_git_repo.rb (57%) create mode 100644 features/steps/project/project_browse_tags.rb create mode 100644 features/steps/project/project_comment_commit.rb rename features/steps/{ => project}/project_issues.rb (80%) rename features/steps/{ => project}/project_labels.rb (62%) rename features/steps/{ => project}/project_merge_requests.rb (73%) rename features/steps/{ => project}/project_milestones.rb (70%) rename features/steps/{ => project}/project_network_graph.rb (76%) rename features/steps/{ => project}/project_team_management.rb (89%) create mode 100644 features/steps/project/project_wall.rb create mode 100644 features/steps/project/project_wiki.rb delete mode 100644 features/steps/project_browse_tags.rb delete mode 100644 features/steps/project_comment_commit.rb delete mode 100644 features/steps/project_wall.rb delete mode 100644 features/steps/project_wiki.rb create mode 100644 features/steps/shared/authentication.rb create mode 100644 features/steps/shared/note.rb create mode 100644 features/steps/shared/paths.rb create mode 100644 features/steps/shared/project.rb diff --git a/features/project/create_project.feature b/features/project/create_project.feature index 42d25b3f..b7cdfdb8 100644 --- a/features/project/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/wall.feature b/features/project/wall.feature index c92dbf82..c38d046a 100644 --- a/features/project/wall.feature +++ b/features/project/wall.feature @@ -1,11 +1,9 @@ -@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 diff --git a/features/steps/dashboard.rb b/features/steps/dashboard/dashboard.rb similarity index 95% rename from features/steps/dashboard.rb rename to features/steps/dashboard/dashboard.rb index e69686b3..6c603bbe 100644 --- a/features/steps/dashboard.rb +++ b/features/steps/dashboard/dashboard.rb @@ -1,4 +1,7 @@ class Dashboard < Spinach::FeatureSteps + include SharedAuthentication + include SharedPaths + Then 'I should see "New Project" link' do page.should have_link "New Project" end @@ -38,10 +41,6 @@ class Dashboard < Spinach::FeatureSteps ) end - When 'I visit dashboard page' do - visit dashboard_path - end - Then 'I should see "John Doe joined project Shop" event' do page.should have_content "John Doe joined project Shop" end @@ -60,10 +59,6 @@ class Dashboard < Spinach::FeatureSteps page.should have_content "John Doe left project Shop" end - Given 'I sign in as a user' do - login_as :user - end - And 'I own project "Shop"' do @project = Factory :project, :name => 'Shop' @project.add_access(@user, :admin) diff --git a/features/steps/dashboard_issues.rb b/features/steps/dashboard/dashboard_issues.rb similarity index 52% rename from features/steps/dashboard_issues.rb rename to features/steps/dashboard/dashboard_issues.rb index 8704d2ef..9368782b 100644 --- a/features/steps/dashboard_issues.rb +++ b/features/steps/dashboard/dashboard_issues.rb @@ -1,4 +1,7 @@ class DashboardIssues < Spinach::FeatureSteps + include SharedAuthentication + include SharedPaths + Then 'I should see issues assigned to me' do issues = @user.issues issues.each do |issue| @@ -7,26 +10,10 @@ class DashboardIssues < Spinach::FeatureSteps end end - Given 'I sign in as a user' do - login_as :user - end - And '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 - - And 'I visit dashboard issues page' do - visit dashboard_issues_path + 2.times { Factory :issue, :author => @user, :assignee => @user, :project => project } end end diff --git a/features/steps/dashboard_merge_requests.rb b/features/steps/dashboard/dashboard_merge_requests.rb similarity index 58% rename from features/steps/dashboard_merge_requests.rb rename to features/steps/dashboard/dashboard_merge_requests.rb index 3e057ef9..fc339e75 100644 --- a/features/steps/dashboard_merge_requests.rb +++ b/features/steps/dashboard/dashboard_merge_requests.rb @@ -1,4 +1,7 @@ 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| @@ -7,10 +10,6 @@ class DashboardMergeRequests < Spinach::FeatureSteps end end - Given 'I sign in as a user' do - login_as :user - end - And 'I have authored merge requests' do project1 = Factory :project project2 = Factory :project @@ -18,16 +17,7 @@ class DashboardMergeRequests < Spinach::FeatureSteps 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 - - And 'I visit dashboard merge requests page' do - visit dashboard_merge_requests_path + 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_search.rb b/features/steps/dashboard/dashboard_search.rb similarity index 74% rename from features/steps/dashboard_search.rb rename to features/steps/dashboard/dashboard_search.rb index 122774fc..e3585898 100644 --- a/features/steps/dashboard_search.rb +++ b/features/steps/dashboard/dashboard_search.rb @@ -1,4 +1,7 @@ class DashboardSearch < Spinach::FeatureSteps + include SharedAuthentication + include SharedPaths + Given 'I search for "Sho"' do fill_in "dashboard_search", :with => "Sho" click_button "Search" @@ -8,16 +11,8 @@ class DashboardSearch < Spinach::FeatureSteps page.should have_link "Shop" end - Given 'I sign in as a user' do - login_as :user - end - And 'I own project "Shop"' do @project = Factory :project, :name => "Shop" @project.add_access(@user, :admin) end - - And 'I visit dashboard search page' do - visit search_path - end end diff --git a/features/steps/profile.rb b/features/steps/profile/profile.rb similarity index 80% rename from features/steps/profile.rb rename to features/steps/profile/profile.rb index c7e6be3f..d3261a16 100644 --- a/features/steps/profile.rb +++ b/features/steps/profile/profile.rb @@ -1,7 +1,6 @@ class Profile < Spinach::FeatureSteps - Given 'I visit profile page' do - visit profile_path - end + include SharedAuthentication + include SharedPaths Then 'I should see my profile info' do page.should have_content "Profile" @@ -23,10 +22,6 @@ class Profile < Spinach::FeatureSteps @user.twitter.should == 'testtwitter' 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" @@ -37,10 +32,6 @@ class Profile < Spinach::FeatureSteps 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" @@ -50,8 +41,4 @@ class Profile < Spinach::FeatureSteps find("#token").value.should_not == @old_token find("#token").value.should == @user.reload.private_token end - - Given 'I sign in as a user' do - login_as :user - end end diff --git a/features/steps/profile_ssh_keys.rb b/features/steps/profile/profile_ssh_keys.rb similarity index 94% rename from features/steps/profile_ssh_keys.rb rename to features/steps/profile/profile_ssh_keys.rb index 9360f66f..96df2d73 100644 --- a/features/steps/profile_ssh_keys.rb +++ b/features/steps/profile/profile_ssh_keys.rb @@ -1,4 +1,6 @@ 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) @@ -40,10 +42,6 @@ class ProfileSshKeys < Spinach::FeatureSteps end end - Given 'I sign in as a user' do - login_as :user - end - And 'I have ssh key "ssh-rsa Work"' do Factory :key, :user => @user, :title => "ssh-rsa Work", :key => "jfKLJDFKSFJSHFJssh-rsa Work" end diff --git a/features/steps/project.rb b/features/steps/project.rb deleted file mode 100644 index 666a65fa..00000000 --- a/features/steps/project.rb +++ /dev/null @@ -1,15 +0,0 @@ -class Projects < Spinach::FeatureSteps - Given 'I sign in as a user' do - login_as :user - end - - And 'I own project "Shop"' do - @project = Factory :project, :name => "Shop" - @project.add_access(@user, :admin) - end - - And 'I visit project "Shop" page' do - project = Project.find_by_name("Shop") - visit project_path(project) - end -end diff --git a/features/steps/create_project.rb b/features/steps/project/create_project.rb similarity index 76% rename from features/steps/create_project.rb rename to features/steps/project/create_project.rb index 80f6f708..6d2ca3f9 100644 --- a/features/steps/create_project.rb +++ b/features/steps/project/create_project.rb @@ -1,11 +1,6 @@ class CreateProject < Spinach::FeatureSteps - Given 'I signin as a user' do - login_as :user - end - - When 'I visit new project page' do - visit new_project_path - end + include SharedAuthentication + include SharedPaths And 'fill project form with valid data' do fill_in 'project_name', :with => 'NewProject' @@ -16,7 +11,7 @@ class CreateProject < Spinach::FeatureSteps Then 'I should see project page' do current_path.should == project_path(Project.last) - page.should have_content('NewProject') + page.should have_content "NewProject" end And 'I should see empty project instuctions' do 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_browse_branches.rb b/features/steps/project/project_browse_branches.rb similarity index 73% rename from features/steps/project_browse_branches.rb rename to features/steps/project/project_browse_branches.rb index 9fb2e59d..2f6e185d 100644 --- a/features/steps/project_browse_branches.rb +++ b/features/steps/project/project_browse_branches.rb @@ -1,4 +1,8 @@ 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" @@ -24,21 +28,8 @@ class ProjectBrowseBranches < Spinach::FeatureSteps end end - Given 'I sign in as a user' do - login_as :user - end - - And 'I own project "Shop"' do - @project = Factory :project, :name => "Shop" - @project.add_access(@user, :admin) - end - And 'project "Shop" has protected branches' do project = Project.find_by_name("Shop") project.protected_branches.create(:name => "stable") end - - Given 'I visit project branches page' do - visit branches_project_repository_path(@project) - end end diff --git a/features/steps/project_browse_commits.rb b/features/steps/project/project_browse_commits.rb similarity index 79% rename from features/steps/project_browse_commits.rb rename to features/steps/project/project_browse_commits.rb index 71c592a7..01479987 100644 --- a/features/steps/project_browse_commits.rb +++ b/features/steps/project/project_browse_commits.rb @@ -1,4 +1,8 @@ class ProjectBrowseCommits < Spinach::FeatureSteps + include SharedAuthentication + include SharedProject + include SharedPaths + Then 'I see project commits' do current_path.should == project_commits_path(@project) @@ -29,10 +33,6 @@ class ProjectBrowseCommits < Spinach::FeatureSteps page.should have_content "Showing 1 changed file" end - Given 'I visit compare refs page' do - visit compare_project_commits_path(@project) - end - And 'I fill compare fields with refs' do fill_in "from", :with => "master" fill_in "to", :with => "stable" @@ -44,17 +44,4 @@ class ProjectBrowseCommits < Spinach::FeatureSteps page.should have_content "Compare View" page.should have_content "Showing 73 changed files" end - - Given 'I sign in as a user' do - login_as :user - end - - And 'I own project "Shop"' do - @project = Factory :project, :name => "Shop" - @project.add_access(@user, :admin) - end - - Given 'I visit project commits page' do - visit project_commits_path(@project) - end end diff --git a/features/steps/project_browse_files.rb b/features/steps/project/project_browse_files.rb similarity index 58% rename from features/steps/project_browse_files.rb rename to features/steps/project/project_browse_files.rb index ad320584..67c553ce 100644 --- a/features/steps/project_browse_files.rb +++ b/features/steps/project/project_browse_files.rb @@ -1,14 +1,14 @@ 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 - Given 'I visit project source page for "8470d70"' do - visit tree_project_ref_path(@project, "8470d70") - 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" @@ -24,10 +24,6 @@ class ProjectBrowseFiles < Spinach::FeatureSteps page.should have_content "rubygems.org" end - Given 'I visit blob file from repo' do - visit tree_project_ref_path(@project, ValidCommit::ID, :path => ValidCommit::BLOB_FILE_PATH) - end - And 'I click link "raw"' do click_link "raw" end @@ -35,17 +31,4 @@ class ProjectBrowseFiles < Spinach::FeatureSteps Then 'I should see raw file content' do page.source.should == ValidCommit::BLOB_FILE end - - Given 'I sign in as a user' do - login_as :user - end - - And 'I own project "Shop"' do - @project = Factory :project, :name => "Shop" - @project.add_access(@user, :admin) - end - - Given 'I visit project source page' do - visit tree_project_ref_path(@project, @project.root_ref) - end end diff --git a/features/steps/project_browse_git_repo.rb b/features/steps/project/project_browse_git_repo.rb similarity index 57% rename from features/steps/project_browse_git_repo.rb rename to features/steps/project/project_browse_git_repo.rb index 56b33a90..e966f407 100644 --- a/features/steps/project_browse_git_repo.rb +++ b/features/steps/project/project_browse_git_repo.rb @@ -1,4 +1,8 @@ class ProjectBrowseGitRepo < Spinach::FeatureSteps + include SharedAuthentication + include SharedProject + include SharedPaths + Given 'I click on "Gemfile" file in repo' do click_link "Gemfile" end @@ -12,17 +16,4 @@ class ProjectBrowseGitRepo < Spinach::FeatureSteps page.should have_content "Dmitriy Zaporozhets" page.should have_content "bc3735004cb Moving to rails 3.2" end - - Given 'I sign in as a user' do - login_as :user - end - - And 'I own project "Shop"' do - @project = Factory :project, :name => "Shop" - @project.add_access(@user, :admin) - end - - Given 'I visit project source page' do - visit tree_project_ref_path(@project, @project.root_ref) - 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_issues.rb b/features/steps/project/project_issues.rb similarity index 80% rename from features/steps/project_issues.rb rename to features/steps/project/project_issues.rb index c3fca0c6..64af2449 100644 --- a/features/steps/project_issues.rb +++ b/features/steps/project/project_issues.rb @@ -1,4 +1,9 @@ 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 @@ -51,20 +56,6 @@ class ProjectIssues < Spinach::FeatureSteps page.should have_content issue.project.name 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 - - And '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 fill in issue search with "Release"' do fill_in 'issue_search', with: "Release" end @@ -90,22 +81,14 @@ class ProjectIssues < Spinach::FeatureSteps project = Project.find_by_name("Shop") milestone = Factory :milestone, :title => "v2.2", :project => project - 3.times do - issue = Factory :issue, :project => project, :milestone => milestone - end + 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 do - issue = Factory :issue, :project => project, :milestone => milestone - end - end - - And 'I visit project "Shop" issues page' do - visit project_issues_path(Project.find_by_name("Shop")) + 3.times { Factory :issue, :project => project, :milestone => milestone } end When 'I select milestone "v3.0"' do @@ -132,15 +115,6 @@ class ProjectIssues < Spinach::FeatureSteps page.find(issues_assignee_selector).should have_content(assignee_name) end - Given 'I sign in as a user' do - login_as :user - end - - And 'I own project "Shop"' do - @project = Factory :project, :name => "Shop" - @project.add_access(@user, :admin) - end - And 'project "Shop" have "Release 0.4" open issue' do project = Project.find_by_name("Shop") Factory.create(:issue, diff --git a/features/steps/project_labels.rb b/features/steps/project/project_labels.rb similarity index 62% rename from features/steps/project_labels.rb rename to features/steps/project/project_labels.rb index 2e83824f..1a347bf3 100644 --- a/features/steps/project_labels.rb +++ b/features/steps/project/project_labels.rb @@ -1,4 +1,8 @@ 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" @@ -11,23 +15,10 @@ class ProjectLabels < Spinach::FeatureSteps end end - Given 'I sign in as a user' do - login_as :user - end - - And 'I own project "Shop"' do - @project = Factory :project, :name => "Shop" - @project.add_access(@user, :admin) - 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 - - Given 'I visit project "Shop" labels page' do - visit project_labels_path(Project.find_by_name("Shop")) - end end diff --git a/features/steps/project_merge_requests.rb b/features/steps/project/project_merge_requests.rb similarity index 73% rename from features/steps/project_merge_requests.rb rename to features/steps/project/project_merge_requests.rb index 8515e7e8..80e83906 100644 --- a/features/steps/project_merge_requests.rb +++ b/features/steps/project/project_merge_requests.rb @@ -1,4 +1,9 @@ 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 @@ -56,29 +61,6 @@ class ProjectMergeRequests < Spinach::FeatureSteps page.should have_content "Wiki Feature" 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 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 sign in as a user' do - login_as :user - end - - And 'I own project "Shop"' do - @project = Factory :project, :name => "Shop" - @project.add_access(@user, :admin) - end - And 'project "Shop" have "Bug NS-04" open merge request' do project = Project.find_by_name("Shop") Factory.create(:merge_request, @@ -95,8 +77,4 @@ class ProjectMergeRequests < Spinach::FeatureSteps :author => project.users.first, :closed => true) end - - And 'I visit project "Shop" merge requests page' do - visit project_merge_requests_path(Project.find_by_name("Shop")) - end end diff --git a/features/steps/project_milestones.rb b/features/steps/project/project_milestones.rb similarity index 70% rename from features/steps/project_milestones.rb rename to features/steps/project/project_milestones.rb index 97574d1c..83ed6859 100644 --- a/features/steps/project_milestones.rb +++ b/features/steps/project/project_milestones.rb @@ -1,4 +1,8 @@ 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]) @@ -26,26 +30,10 @@ class ProjectMilestones < Spinach::FeatureSteps page.should have_content("Browse Issues") end - Given 'I sign in as a user' do - login_as :user - end - - And 'I own project "Shop"' do - @project = Factory :project, :name => "Shop" - @project.add_access(@user, :admin) - 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 do - issue = Factory :issue, :project => project, :milestone => milestone - end - end - - Given 'I visit project "Shop" milestones page' do - @project = Project.find_by_name("Shop") - visit project_milestones_path(@project) + 3.times { Factory :issue, :project => project, :milestone => milestone } end end diff --git a/features/steps/project_network_graph.rb b/features/steps/project/project_network_graph.rb similarity index 76% rename from features/steps/project_network_graph.rb rename to features/steps/project/project_network_graph.rb index d87f3d82..f34a81a4 100644 --- a/features/steps/project_network_graph.rb +++ b/features/steps/project/project_network_graph.rb @@ -1,4 +1,7 @@ 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 @@ -7,15 +10,6 @@ class ProjectNetworkGraph < Spinach::FeatureSteps end end - Given 'I sign in as a user' do - login_as :user - end - - And 'I own project "Shop"' do - @project = Factory :project, :name => "Shop" - @project.add_access(@user, :admin) - end - And 'I visit project "Shop" network page' do project = Project.find_by_name("Shop") diff --git a/features/steps/project_team_management.rb b/features/steps/project/project_team_management.rb similarity index 89% rename from features/steps/project_team_management.rb rename to features/steps/project/project_team_management.rb index 9cee75bd..7beca257 100644 --- a/features/steps/project_team_management.rb +++ b/features/steps/project/project_team_management.rb @@ -1,4 +1,8 @@ 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) @@ -42,10 +46,6 @@ class ProjectTeamManagement < Spinach::FeatureSteps end end - Then 'I visit project "Shop" team page' do - visit team_project_path(Project.find_by_name("Shop")) - 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 @@ -73,15 +73,6 @@ class ProjectTeamManagement < Spinach::FeatureSteps page.should_not have_content(user.email) end - Given 'I sign in as a user' do - login_as :user - end - - And 'I own project "Shop"' do - @project = Factory :project, :name => "Shop" - @project.add_access(@user, :admin) - end - And 'gitlab user "Mike"' do Factory :user, :name => "Mike" 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/project_browse_tags.rb b/features/steps/project_browse_tags.rb deleted file mode 100644 index c6bea691..00000000 --- a/features/steps/project_browse_tags.rb +++ /dev/null @@ -1,19 +0,0 @@ -class ProjectBrowseTags < Spinach::FeatureSteps - Then 'I should see "Shop" all tags list' do - page.should have_content "Tags" - page.should have_content "v1.2.1" - end - - Given 'I sign in as a user' do - login_as :user - end - - And 'I own project "Shop"' do - @project = Factory :project, :name => "Shop" - @project.add_access(@user, :admin) - end - - Given 'I visit project tags page' do - visit tags_project_repository_path(@project) - end -end diff --git a/features/steps/project_comment_commit.rb b/features/steps/project_comment_commit.rb deleted file mode 100644 index 04e94c7d..00000000 --- a/features/steps/project_comment_commit.rb +++ /dev/null @@ -1,23 +0,0 @@ -class ProjectCommentCommit < Spinach::FeatureSteps - 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 sign in as a user' do - login_as :user - end - - And 'I own project "Shop"' do - @project = Factory :project, :name => "Shop" - @project.add_access(@user, :admin) - end - - Given 'I visit project commit page' do - visit project_commit_path(@project, ValidCommit::ID) - end -end diff --git a/features/steps/project_wall.rb b/features/steps/project_wall.rb deleted file mode 100644 index b94bd0bb..00000000 --- a/features/steps/project_wall.rb +++ /dev/null @@ -1,24 +0,0 @@ -class ProjectWall < Spinach::FeatureSteps - 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 - - Then 'I visit project "Shop" wall page' do - project = Project.find_by_name("Shop") - visit wall_project_path(project) - end - - Given 'I signin as a user' do - login_as :user - end - - And 'I own project "Shop"' do - @project = Factory :project, :name => "Shop" - @project.add_access(@user, :admin) - end -end diff --git a/features/steps/project_wiki.rb b/features/steps/project_wiki.rb deleted file mode 100644 index 8c8c7c8d..00000000 --- a/features/steps/project_wiki.rb +++ /dev/null @@ -1,37 +0,0 @@ -class ProjectWiki < Spinach::FeatureSteps - 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 - - And '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 sign in as a user' do - login_as :user - end - - And 'I own project "Shop"' do - @project = Factory :project, :name => "Shop" - @project.add_access(@user, :admin) - end - - Given 'I visit project wiki page' do - visit project_wiki_path(@project, :index) - 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..05ae88e6 --- /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 password page' do + visit profile_password_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 team_project_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 7bd89801..9c6cef07 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -5,11 +5,12 @@ require 'rspec' require 'database_cleaner' require 'spinach/capybara' -%w(gitolite_stub login_helpers stubbed_repository valid_commit).each do |f| +%w(gitolite_stub stubbed_repository valid_commit).each do |f| require Rails.root.join('spec', 'support', f) end -include LoginHelpers +Dir["#{Rails.root}/features/steps/shared/*.rb"].each {|file| require file} + include GitoliteStub WebMock.allow_net_connect! From a2f7f48c034bc32fe626980ed88f8789b19b36bd Mon Sep 17 00:00:00 2001 From: randx Date: Mon, 10 Sep 2012 19:50:35 +0300 Subject: [PATCH 038/123] Ask guard not to run all tests on start --- Guardfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Guardfile b/Guardfile index 6ed414bc..0eea2ad9 100644 --- a/Guardfile +++ b/Guardfile @@ -1,7 +1,7 @@ # A sample Guardfile # More info at https://github.com/guard/guard#readme -guard 'rspec', :version => 2 do +guard 'rspec', :version => 2, :all_on_start => false do watch(%r{^spec/.+_spec\.rb$}) watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } watch('spec/spec_helper.rb') { "spec" } From 96d4f22e53a6176715f9557fb0707cb166a1dd80 Mon Sep 17 00:00:00 2001 From: Saito Date: Tue, 11 Sep 2012 19:18:14 +0800 Subject: [PATCH 039/123] tree view need use ascii-8bit, file name need be utf8. --- app/helpers/tree_helper.rb | 3 ++- app/models/tree.rb | 2 +- app/views/refs/_tree_file.html.haml | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb index c51ee84a..a5d5c742 100644 --- a/app/helpers/tree_helper.rb +++ b/app/helpers/tree_helper.rb @@ -18,7 +18,8 @@ module TreeHelper end def tree_full_path(content) - if params[:path] + content.name.force_encoding('utf-8') + if params[:path] File.join(params[:path], content.name) else content.name diff --git a/app/models/tree.rb b/app/models/tree.rb index bc95d335..d65e50ab 100644 --- a/app/models/tree.rb +++ b/app/models/tree.rb @@ -16,7 +16,7 @@ class Tree def initialize(raw_tree, project, ref = nil, path = nil) @project, @ref, @path = project, ref, path, @tree = if path - raw_tree / path + raw_tree / path.dup.force_encoding('ascii-8bit') else raw_tree end diff --git a/app/views/refs/_tree_file.html.haml b/app/views/refs/_tree_file.html.haml index 765f271a..f6566ccf 100644 --- a/app/views/refs/_tree_file.html.haml +++ b/app/views/refs/_tree_file.html.haml @@ -2,7 +2,7 @@ .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" From 5a9071264576e672da998d6d346bc5200ae91153 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Tue, 11 Sep 2012 05:35:16 -0700 Subject: [PATCH 040/123] don't load commit logs when viewing blob --- app/views/refs/_tree.html.haml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/views/refs/_tree.html.haml b/app/views/refs/_tree.html.haml index 83e73280..ec6dba4e 100644 --- a/app/views/refs/_tree.html.haml +++ b/app/views/refs/_tree.html.haml @@ -50,11 +50,12 @@ 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 From f7c70eaaedd196accbe8e952ddc4738a96b81998 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Tue, 11 Sep 2012 16:47:59 +0200 Subject: [PATCH 041/123] Add *votes_in_percent --- app/roles/votes.rb | 16 +++++++++++++ spec/roles/votes_spec.rb | 50 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/app/roles/votes.rb b/app/roles/votes.rb index 3a584d8b..043a6feb 100644 --- a/app/roles/votes.rb +++ b/app/roles/votes.rb @@ -4,11 +4,27 @@ module Votes notes.select(&:upvote?).size end + def upvotes_in_percent + if votes_count.zero? + 0 + else + 100.0 / votes_count * upvotes + end + end + # Return the number of -1 comments (downvotes) def downvotes notes.select(&:downvote?).size end + def downvotes_in_percent + if votes_count.zero? + 0 + else + 100.0 - upvotes_in_percent + end + end + # Return the total number of votes def votes_count upvotes + downvotes diff --git a/spec/roles/votes_spec.rb b/spec/roles/votes_spec.rb index 5c3548a5..98666022 100644 --- a/spec/roles/votes_spec.rb +++ b/spec/roles/votes_spec.rb @@ -79,4 +79,54 @@ describe Issue do issue.votes_count.should == 3 end end + + describe "#upvotes_in_percent" do + it "with no notes has a 0% score" do + issue.upvotes_in_percent.should == 0 + end + + it "should count a single 1 note as 100%" do + issue.notes << create(:note, note: "+1 This is awesome") + issue.upvotes_in_percent.should == 100 + end + + it "should count multiple +1 notes as 100%" do + issue.notes << create(:note, note: "+1 This is awesome") + issue.notes << create(:note, note: "+1 I want this") + issue.upvotes_in_percent.should == 100 + end + + it "should count fractions for multiple +1 and -1 notes correctly" do + issue.notes << create(:note, note: "+1 This is awesome") + issue.notes << create(:note, note: "+1 I want this") + issue.notes << create(:note, note: "-1 This is bad") + issue.notes << create(:note, note: "+1 me too") + issue.upvotes_in_percent.should == 75 + end + end + + describe "#downvotes_in_percent" do + it "with no notes has a 0% score" do + issue.downvotes_in_percent.should == 0 + end + + it "should count a single -1 note as 100%" do + issue.notes << create(:note, note: "-1 This is bad") + issue.downvotes_in_percent.should == 100 + end + + it "should count multiple -1 notes as 100%" do + issue.notes << create(:note, note: "-1 This is bad") + issue.notes << create(:note, note: "-1 Away with this") + issue.downvotes_in_percent.should == 100 + end + + it "should count fractions for multiple +1 and -1 notes correctly" do + issue.notes << create(:note, note: "+1 This is awesome") + issue.notes << create(:note, note: "+1 I want this") + issue.notes << create(:note, note: "-1 This is bad") + issue.notes << create(:note, note: "+1 me too") + issue.downvotes_in_percent.should == 25 + end + end end From 0bfcc574b660108646bd2c99a611163a0c847251 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Mon, 10 Sep 2012 15:27:14 +0200 Subject: [PATCH 042/123] Extract displaying votes into partials --- app/views/issues/_show.html.haml | 9 +-------- app/views/issues/show.html.haml | 9 +-------- app/views/merge_requests/_merge_request.html.haml | 10 ++-------- app/views/merge_requests/show/_mr_title.html.haml | 9 +-------- app/views/votes/_votes_block.html.haml | 6 ++++++ app/views/votes/_votes_inline.html.haml | 6 ++++++ 6 files changed, 17 insertions(+), 32 deletions(-) create mode 100644 app/views/votes/_votes_block.html.haml create mode 100644 app/views/votes/_votes_inline.html.haml diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml index db394873..22101aa1 100644 --- a/app/views/issues/_show.html.haml +++ b/app/views/issues/_show.html.haml @@ -35,11 +35,4 @@   - if issue.votes_count > 0 - .votes.votes-inline - .upvotes= issue.upvotes - .progress - - up_percent = 100.0/issue.votes_count*issue.upvotes - - down_percent = 100.0-up_percent - .bar.bar-success{style: "width: #{up_percent}%;"} - .bar.bar-danger{style: "width: #{down_percent}%;"} - .downvotes= issue.downvotes + = render 'votes/votes_inline', votable: issue diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index 1ec03951..9b1c72a3 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -17,14 +17,7 @@ Edit .right - .span3.votes.votes-block#votes - .progress - - up_percent = 100.0/@issue.votes_count*@issue.upvotes - - down_percent = 100.0-up_percent - .bar.bar-success{style: "width: #{up_percent}%;"} - .bar.bar-danger{style: "width: #{down_percent}%;"} - .upvotes= "#{@issue.upvotes} up" - .downvotes= "#{@issue.downvotes} down" + .span3#votes= render 'votes/votes_block', votable: @issue .back_link = link_to project_issues_path(@project) do diff --git a/app/views/merge_requests/_merge_request.html.haml b/app/views/merge_requests/_merge_request.html.haml index 08420fd2..9d94d670 100644 --- a/app/views/merge_requests/_merge_request.html.haml +++ b/app/views/merge_requests/_merge_request.html.haml @@ -23,12 +23,6 @@ authored by #{merge_request.author_name} = time_ago_in_words(merge_request.created_at) ago + - if merge_request.votes_count > 0 - .votes.votes-inline - .upvotes= merge_request.upvotes - .progress - - up_percent = 100.0/merge_request.votes_count*merge_request.upvotes - - down_percent = 100.0-up_percent - .bar.bar-success{style: "width: #{up_percent}%;"} - .bar.bar-danger{style: "width: #{down_percent}%;"} - .downvotes= merge_request.downvotes + = render 'votes/votes_inline', votable: merge_request diff --git a/app/views/merge_requests/show/_mr_title.html.haml b/app/views/merge_requests/show/_mr_title.html.haml index c0ad4be5..8708469c 100644 --- a/app/views/merge_requests/show/_mr_title.html.haml +++ b/app/views/merge_requests/show/_mr_title.html.haml @@ -24,14 +24,7 @@ Edit .right - .span3.votes.votes-block#votes - .progress - - up_percent = 100.0/@merge_request.votes_count*@merge_request.upvotes - - down_percent = 100.0-up_percent - .bar.bar-success{style: "width: #{up_percent}%;"} - .bar.bar-danger{style: "width: #{down_percent}%;"} - .upvotes= "#{@merge_request.upvotes} up" - .downvotes= "#{@merge_request.downvotes} down" + .span3#votes= render 'votes/votes_block', votable: @merge_request .back_link = link_to project_merge_requests_path(@project) do 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 From 0523b4265bb19bfff15c6a435dd52ffd6a5683f8 Mon Sep 17 00:00:00 2001 From: randx Date: Tue, 11 Sep 2012 23:24:53 +0300 Subject: [PATCH 043/123] Application logger --- app/assets/javascripts/admin.js.coffee | 4 +++ app/assets/javascripts/application.js | 2 +- app/assets/stylesheets/sections/nav.scss | 1 - app/observers/project_observer.rb | 12 ++++++++ app/observers/user_observer.rb | 12 ++++++++ app/views/admin/logs/show.html.haml | 35 ++++++++++++++++++------ lib/gitlab/app_logger.rb | 11 ++++++++ lib/gitlab/backend/gitolite_config.rb | 10 +++++-- lib/gitlab/git_logger.rb | 11 ++++++++ lib/gitlab/logger.rb | 8 ++---- 10 files changed, 86 insertions(+), 20 deletions(-) create mode 100644 lib/gitlab/app_logger.rb create mode 100644 lib/gitlab/git_logger.rb diff --git a/app/assets/javascripts/admin.js.coffee b/app/assets/javascripts/admin.js.coffee index 269a7a76..76454c29 100644 --- a/app/assets/javascripts/admin.js.coffee +++ b/app/assets/javascripts/admin.js.coffee @@ -6,3 +6,7 @@ $ -> 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 4c487ec1..f9fdb0f7 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -11,7 +11,7 @@ //= require jquery.endless-scroll //= require jquery.highlight //= require jquery.waitforimages -//= require bootstrap-modal +//= require bootstrap //= require modernizr //= require chosen-jquery //= require raphael diff --git a/app/assets/stylesheets/sections/nav.scss b/app/assets/stylesheets/sections/nav.scss index 6f6a0e8e..2d902918 100644 --- a/app/assets/stylesheets/sections/nav.scss +++ b/app/assets/stylesheets/sections/nav.scss @@ -55,7 +55,6 @@ ul.main_menu { &.current { background-color:#D5D5D5; - border-bottom: 1px solid #AAA; border-right: 1px solid #BBB; border-left: 1px solid #BBB; border-radius: 0 0 1px 1px; diff --git a/app/observers/project_observer.rb b/app/observers/project_observer.rb index 135959ab..03a61709 100644 --- a/app/observers/project_observer.rb +++ b/app/observers/project_observer.rb @@ -4,6 +4,18 @@ class ProjectObserver < ActiveRecord::Observer end def after_destroy(project) + log_info("Project \"#{project.name}\" was removed") + project.destroy_repository end + + def after_create project + log_info("#{project.owner.name} created a new project \"#{project.name}\"") + end + + protected + + def log_info message + Gitlab::AppLogger.info message + end end diff --git a/app/observers/user_observer.rb b/app/observers/user_observer.rb index d12bcc99..654621f7 100644 --- a/app/observers/user_observer.rb +++ b/app/observers/user_observer.rb @@ -1,5 +1,17 @@ class UserObserver < ActiveRecord::Observer def after_create(user) + log_info("User \"#{user.name}\" (#{user.email}) was created") + Notify.new_user_email(user.id, user.password).deliver end + + def after_destroy user + log_info("User \"#{user.name}\" (#{user.email}) was removed") + end + + protected + + def log_info message + Gitlab::AppLogger.info message + end end diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml index 800d3bb2..0efe6db7 100644 --- a/app/views/admin/logs/show.html.haml +++ b/app/views/admin/logs/show.html.haml @@ -1,9 +1,26 @@ -.file_holder#README - .file_title - %i.icon-file - githost.log - .file_content.logs - %ol - - Gitlab::Logger.read_latest.each do |line| - %li - %p= line +%ul.nav.nav-tabs.log-tabs + %li.active + = link_to "githost.log", "#githost", 'data-toggle' => 'tab' + %li + = link_to "application.log", "#application", 'data-toggle' => 'tab' +.tab-content + .tab-pane.active#githost + .file_holder#README + .file_title + %i.icon-file + githost.log + .file_content.logs + %ol + - Gitlab::GitLogger.read_latest.each do |line| + %li + %p= line + .tab-pane#application + .file_holder#README + .file_title + %i.icon-file + application.log + .file_content.logs + %ol + - Gitlab::AppLogger.read_latest.each do |line| + %li + %p= line 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/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb index 0d636d2d..f51e8efc 100644 --- a/lib/gitlab/backend/gitolite_config.rb +++ b/lib/gitlab/backend/gitolite_config.rb @@ -58,18 +58,22 @@ module Gitlab end end rescue PullError => ex - Gitlab::Logger.error("Pull error -> " + ex.message) + log("Pull error -> " + ex.message) raise Gitolite::AccessDenied, ex.message rescue PushError => ex - Gitlab::Logger.error("Push error -> " + " " + ex.message) + log("Push error -> " + " " + ex.message) raise Gitolite::AccessDenied, ex.message rescue Exception => ex - Gitlab::Logger.error(ex.class.name + " " + ex.message) + 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) 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/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 From 486de8c3f412df3e71c9045faf250941c03c8c00 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 12 Sep 2012 07:48:22 +0300 Subject: [PATCH 044/123] Refactoring auth --- Gemfile.lock | 32 +++++++++++++++ app/assets/stylesheets/auth_methods.scss | 4 +- app/views/devise/sessions/new.html.erb | 32 --------------- config/gitlab.yml.example | 50 +++++++++++++++--------- config/initializers/1_settings.rb | 10 ++++- config/initializers/devise.rb | 17 ++++++++ config/initializers/omniauth.rb.sample | 15 ------- 7 files changed, 91 insertions(+), 69 deletions(-) delete mode 100644 app/views/devise/sessions/new.html.erb delete mode 100644 config/initializers/omniauth.rb.sample diff --git a/Gemfile.lock b/Gemfile.lock index 8046b92b..3d27d3fb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -158,6 +158,8 @@ GEM 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) @@ -194,6 +196,7 @@ GEM httparty (0.8.3) multi_json (~> 1.0) multi_xml + httpauth (0.1) i18n (0.6.1) journey (1.0.4) jquery-rails (2.0.2) @@ -203,6 +206,8 @@ GEM jquery-rails railties (>= 3.1.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) @@ -225,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) @@ -420,7 +448,11 @@ 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 diff --git a/app/assets/stylesheets/auth_methods.scss b/app/assets/stylesheets/auth_methods.scss index ed6f5b0f..f94a0e52 100644 --- a/app/assets/stylesheets/auth_methods.scss +++ b/app/assets/stylesheets/auth_methods.scss @@ -1,9 +1,9 @@ .auth_methods { - &ul { + ul { margin: 0; text-align:center; padding: 5px; - &li { + li { display: inline; } } diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb deleted file mode 100644 index 6b334b87..00000000 --- a/app/views/devise/sessions/new.html.erb +++ /dev/null @@ -1,32 +0,0 @@ -<% unless ldap_enable? -%> - - <%= form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { :class => "login-box" }) do |f| %> - <%= image_tag "login-logo.png", :width => "304", :height => "66", :class => "login-logo", :alt => "Login Logo" %> - - <%= f.text_field :email, :class => "text top", :placeholder => "Email" %> - <%= f.password_field :password, :class => "text bottom", :placeholder => "Password" %> - - <% if devise_mapping.rememberable? -%> -
- <% end -%> -
- <%= f.submit "Sign in", :class => "primary btn" %> -
<%= render :partial => "devise/shared/links" %>
- - <%- if devise_mapping.omniauthable? %> -
-
-
    - <%- resource_class.omniauth_providers.each do |provider| %> -
  • <%= link_to authbutton(provider), - omniauth_authorize_path(resource_name, provider) %>
  • - <% end -%> -
-
- <% end -%> - - <% end %> - -<% else %> - <%= render :partial => 'devise/sessions/new_ldap' %> -<% end %> diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 809d7ee9..a52bc1b9 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -25,8 +25,38 @@ 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: + enabled: false + allow_single_sign_on: false + block_auto_created_users: true + 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 @@ -50,21 +80,3 @@ git: git_max_size: 5242880 # 5.megabytes # Git timeout to read commit, in seconds git_timeout: 10 - -# Omniauth configuration -omniauth: - enabled: false - providers: - allow_single_sign_on: false - block_auto_created_users: true - -# omniauth: -# enabled: true -# 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' } diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 00b7cc09..326f5af2 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -120,8 +120,16 @@ class Settings < Settingslogic app['backup_keep_time'] || 0 end + def ldap_enabled? + ldap['enabled'] + rescue + false + end + def omniauth_enabled? - omniauth['enabled'] || false + omniauth && omniauth['enabled'] + rescue + false end def omniauth_providers 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/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 From fa4150d47d88b85d6027729844480a3e7c71d3cd Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 12 Sep 2012 08:23:20 +0300 Subject: [PATCH 045/123] Cleanup after omniauth --- app/assets/stylesheets/auth_methods.scss | 10 ----- .../stylesheets/gitlab_bootstrap/blocks.scss | 4 ++ app/assets/stylesheets/main.scss | 1 - .../omniauth_callbacks_controller.rb | 11 +++-- app/helpers/application_helper.rb | 5 ++- app/views/devise/sessions/new.html.haml | 9 ++-- app/views/profile/password.html.haml | 6 +-- app/views/profile/show.html.haml | 44 +++++++++++-------- config/gitlab.yml.example | 6 ++- 9 files changed, 49 insertions(+), 47 deletions(-) delete mode 100644 app/assets/stylesheets/auth_methods.scss diff --git a/app/assets/stylesheets/auth_methods.scss b/app/assets/stylesheets/auth_methods.scss deleted file mode 100644 index f94a0e52..00000000 --- a/app/assets/stylesheets/auth_methods.scss +++ /dev/null @@ -1,10 +0,0 @@ -.auth_methods { - ul { - margin: 0; - text-align:center; - padding: 5px; - li { - display: inline; - } - } -} diff --git a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss index 70f7889f..e0ae8db7 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss @@ -142,4 +142,8 @@ border:none; } } + + .ui-box-body { + padding:10px; + } } diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss index 201c69f4..9a6d4456 100644 --- a/app/assets/stylesheets/main.scss +++ b/app/assets/stylesheets/main.scss @@ -134,7 +134,6 @@ $hover: #fdf5d9; * TODO: clean it */ @import "common.scss"; -@import "auth_methods.scss"; /** * Styles related to specific part of app diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index 3be285ba..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 @@ -19,12 +24,6 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController sign_in_and_redirect @user end - Settings.omniauth_providers.each do |provider| - define_method provider['name'] do - handle_omniauth - end - end - private def handle_omniauth diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 7033daf8..fb1393e2 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -137,7 +137,8 @@ module ApplicationHelper end def authbutton(provider, size = 64) - image_tag("authbuttons/#{provider.to_s.split('_').first}_#{size}.png", - alt: "Sign in with #{provider.to_s.titleize}" ) + 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/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index 6e86186c..e217cba6 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -15,7 +15,8 @@ .right = render :partial => "devise/shared/links" - if devise_mapping.omniauthable? - - resource_class.omniauth_providers.each do |provider| - %hr/ - = link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider), :class => "btn primary" - %br/ + %hr/ + %ul.unstyled + - resource_class.omniauth_providers.each do |provider| + %li + = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider) diff --git a/app/views/profile/password.html.haml b/app/views/profile/password.html.haml index 2405b9d7..bf58e2ae 100644 --- a/app/views/profile/password.html.haml +++ b/app/views/profile/password.html.haml @@ -19,11 +19,11 @@ = f.label :password_confirmation .input= f.password_field :password_confirmation - - if Settings.omniauth.enabled + - if Gitlab.config.omniauth_enabled? .span5.right - .auth_methods.alert.alert-info + .alert.alert-info %strong Tip: Use one of the following sites to login - %ul + %ul.unstyled - User.omniauth_providers.each do |provider| %li= link_to authbutton(provider), | omniauth_authorize_path(User, provider) | diff --git a/app/views/profile/show.html.haml b/app/views/profile/show.html.haml index 1e53ead6..8369da4c 100644 --- a/app/views/profile/show.html.haml +++ b/app/views/profile/show.html.haml @@ -50,28 +50,34 @@ %strong Tip: You can change your avatar at gravatar.com - - if Settings.omniauth.enabled && @user.provider? - %h4 - Omniauth Providers: - = link_to "Change", profile_password_path, class: "btn small right" - You can login through #{@user.provider.titleize}! - = authbutton(@user.provider, 32) + - @user.provider = 'twitter' + - if Gitlab.config.omniauth_enabled? && @user.provider? + .ui-box + .ui-box-body + %h4 + Omniauth Providers: + = link_to "Change", profile_password_path, class: "btn small right" + You can login through #{@user.provider.titleize}! + = authbutton(@user.provider, 32) - %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}%;"} + .ui-box + .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}%;"} - %h4 - SSH public keys: - %small.right - %span= link_to current_user.keys.count, keys_path + .ui-box + .ui-box-body + %h4 + SSH public keys: + %strong.right= 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 save-btn" diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index a52bc1b9..3e4668ce 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -43,8 +43,6 @@ ldap: omniauth: enabled: false - allow_single_sign_on: false - block_auto_created_users: true providers: # - { name: 'google_oauth2', app_id: 'YOUR APP ID', # app_secret: 'YOUR APP SECRET', @@ -53,6 +51,10 @@ omniauth: # app_secret: 'YOUR APP SECRET'} # - { name: 'github', app_id: 'YOUR APP ID', # app_secret: 'YOUR APP SECRET' } + # IMPORTANT! + # It allows user to login without having user account + allow_single_sign_on: false + block_auto_created_users: true # From d8f6d38d39868426902ffbad9c232b7748a4288f Mon Sep 17 00:00:00 2001 From: randx Date: Wed, 12 Sep 2012 09:05:12 +0300 Subject: [PATCH 046/123] Fix observer test --- spec/observers/user_observer_spec.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spec/observers/user_observer_spec.rb b/spec/observers/user_observer_spec.rb index 23dac98b..0420a250 100644 --- a/spec/observers/user_observer_spec.rb +++ b/spec/observers/user_observer_spec.rb @@ -13,7 +13,7 @@ describe UserObserver do end context 'when a new user is created' do - let(:user) { double(:user, id: 42, password: 'P@ssword!') } + let(:user) { double(:user, id: 42, password: 'P@ssword!', name: 'John', email: 'u@mail.local') } let(:notification) { double :notification } it 'sends an email' do @@ -22,5 +22,10 @@ describe UserObserver do subject.after_create(user) end + + it 'trigger logger' do + Gitlab::AppLogger.should_receive(:info) + subject.after_create(user) + end end end From 048d47e6266b5b078a169f1657d07883e86f169b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 12 Sep 2012 09:23:16 +0300 Subject: [PATCH 047/123] Refactorn oauth & ldap --- app/models/user.rb | 57 +++--------------------- config/gitlab.yml.example | 15 ++++--- lib/gitlab/auth.rb | 66 +++++++++++++++++++++++++++ spec/lib/auth_spec.rb | 93 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 176 insertions(+), 55 deletions(-) create mode 100644 lib/gitlab/auth.rb create mode 100644 spec/lib/auth_spec.rb diff --git a/app/models/user.rb b/app/models/user.rb index fa5d6834..47876722 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -87,62 +87,19 @@ class User < ActiveRecord::Base end def self.create_from_omniauth(auth, ldap = false) - provider, uid = auth.provider, 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? - - logger.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 + gitlab_auth.create_from_omniauth(auth, ldap) end def self.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 = User.create_from_omniauth(auth) - @user - end - end + gitlab_auth.find_or_new_for_omniauth(auth) end - def self.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? + def self.find_for_ldap_auth(auth, signed_in_resource = nil) + gitlab_auth.find_for_ldap_auth(auth, signed_in_resource) + end - if @user = User.find_by_extern_uid_and_provider(uid, provider) - @user - # workaround for backward compatibility - elsif @user = User.find_by_email(email) - logger.info "Updating legacy LDAP user #{email} with extern_uid => #{uid}" - @user.update_attributes(:extern_uid => uid, :provider => provider) - @user - else - create_from_omniauth(auth) - end + def self.gitlab_auth + Gitlab::Auth.new end def self.search query diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 3e4668ce..80d95b26 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -42,7 +42,16 @@ ldap: password: '_the_password_of_the_bind_user' omniauth: - enabled: false + # Enable ability for users + # to login via twitter, google .. + enabled: true + + # 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', @@ -51,10 +60,6 @@ omniauth: # app_secret: 'YOUR APP SECRET'} # - { name: 'github', app_id: 'YOUR APP ID', # app_secret: 'YOUR APP SECRET' } - # IMPORTANT! - # It allows user to login without having user account - allow_single_sign_on: false - block_auto_created_users: true # diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb new file mode 100644 index 00000000..ef058ff5 --- /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/spec/lib/auth_spec.rb b/spec/lib/auth_spec.rb new file mode 100644 index 00000000..5faf1307 --- /dev/null +++ b/spec/lib/auth_spec.rb @@ -0,0 +1,93 @@ +require 'spec_helper' + +describe Gitlab::Auth do + let(:gl_auth) { Gitlab::Auth.new } + + before do + @info = mock( + uid: '12djsak321', + name: 'John', + email: 'john@mail.com' + ) + end + + describe :find_for_ldap_auth do + before do + @auth = mock( + uid: '12djsak321', + info: @info, + provider: 'ldap' + ) + end + + it "should find by uid & provider" do + User.should_receive :find_by_extern_uid_and_provider + gl_auth.find_for_ldap_auth(@auth) + end + + it "should update credentials by email if missing uid" do + user = double('User') + User.stub find_by_extern_uid_and_provider: nil + User.stub find_by_email: user + user.should_receive :update_attributes + gl_auth.find_for_ldap_auth(@auth) + end + + + it "should create from auth if user doesnot exist"do + User.stub find_by_extern_uid_and_provider: nil + User.stub find_by_email: nil + gl_auth.should_receive :create_from_omniauth + gl_auth.find_for_ldap_auth(@auth) + end + end + + describe :find_or_new_for_omniauth do + before do + @auth = mock( + info: @info, + provider: 'twitter', + uid: '12djsak321', + ) + end + + it "should find user"do + User.should_receive :find_by_provider_and_extern_uid + gl_auth.should_not_receive :create_from_omniauth + gl_auth.find_or_new_for_omniauth(@auth) + end + + it "should not create user"do + User.stub find_by_provider_and_extern_uid: nil + gl_auth.should_not_receive :create_from_omniauth + gl_auth.find_or_new_for_omniauth(@auth) + end + + it "should create user if single_sing_on"do + Gitlab.config.omniauth.stub allow_single_sign_on: true + User.stub find_by_provider_and_extern_uid: nil + gl_auth.should_receive :create_from_omniauth + gl_auth.find_or_new_for_omniauth(@auth) + end + end + + describe :create_from_omniauth do + it "should create user from LDAP" do + @auth = mock(info: @info, provider: 'ldap') + user = gl_auth.create_from_omniauth(@auth, true) + + user.should be_valid + user.extern_uid.should == @info.uid + user.provider.should == 'ldap' + end + + it "should create user from Omniauth" do + @auth = mock(info: @info, provider: 'twitter') + user = gl_auth.create_from_omniauth(@auth, false) + + user.should be_valid + user.extern_uid.should == @info.uid + user.provider.should == 'twitter' + end + end +end From a87c268f7d3b083534a76065040aa78744c46862 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Wed, 12 Sep 2012 05:01:50 -0700 Subject: [PATCH 048/123] remove duplicate code from atom request specs --- spec/requests/atom/dashboard_issues_spec.rb | 45 +++++------------ spec/requests/atom/dashboard_spec.rb | 32 +++++------- spec/requests/atom/issues_spec.rb | 54 +++++++++------------ 3 files changed, 50 insertions(+), 81 deletions(-) diff --git a/spec/requests/atom/dashboard_issues_spec.rb b/spec/requests/atom/dashboard_issues_spec.rb index 79a9b8ef..8d1111fc 100644 --- a/spec/requests/atom/dashboard_issues_spec.rb +++ b/spec/requests/atom/dashboard_issues_spec.rb @@ -1,42 +1,23 @@ require 'spec_helper' -describe "User Issues Dashboard" do +describe "Dashboard Issues Feed" do describe "GET /issues" do - before do + let!(:user) { Factory :user } + let!(:project1) { Factory :project } + let!(:project2) { Factory :project } + let!(:issue1) { Factory :issue, author: user, assignee: user, project: project1 } + let!(:issue2) { Factory :issue, author: user, assignee: user, project: project2 } - login_as :user - - @project1 = Factory :project - - @project2 = Factory :project - - @project1.add_access(@user, :read, :write) - @project2.add_access(@user, :read, :write) - - @issue1 = Factory :issue, - author: @user, - assignee: @user, - project: @project1 - - @issue2 = Factory :issue, - author: @user, - assignee: @user, - project: @project2 - - visit dashboard_issues_path - end - - describe "atom feed", js: false do + describe "atom feed" do it "should render atom feed via private token" do - logout - visit dashboard_issues_path(:atom, private_token: @user.private_token) + visit dashboard_issues_path(:atom, private_token: user.private_token) page.response_headers['Content-Type'].should have_content("application/atom+xml") - page.body.should have_selector("title", text: "#{@user.name} issues") - page.body.should have_selector("author email", text: @issue1.author_email) - page.body.should have_selector("entry summary", text: @issue1.title) - page.body.should have_selector("author email", text: @issue2.author_email) - page.body.should have_selector("entry summary", text: @issue2.title) + page.body.should have_selector("title", text: "#{user.name} issues") + page.body.should have_selector("author email", text: issue1.author_email) + page.body.should have_selector("entry summary", text: issue1.title) + page.body.should have_selector("author email", text: issue2.author_email) + page.body.should have_selector("entry summary", text: issue2.title) end end end diff --git a/spec/requests/atom/dashboard_spec.rb b/spec/requests/atom/dashboard_spec.rb index 00c7a525..9459dd01 100644 --- a/spec/requests/atom/dashboard_spec.rb +++ b/spec/requests/atom/dashboard_spec.rb @@ -1,27 +1,21 @@ require 'spec_helper' -describe "User Dashboard" do - before { login_as :user } - +describe "Dashboard Feed" do describe "GET /" do - before do - @project = Factory :project, owner: @user - @project.add_access(@user, :read) - visit dashboard_path + let!(:user) { Factory :user } + + context "projects atom feed via private token" do + it "should render projects atom feed" do + visit dashboard_path(:atom, private_token: user.private_token) + page.body.should have_selector("feed title") + end end - it "should render projects atom feed via private token" do - logout - - visit dashboard_path(:atom, private_token: @user.private_token) - page.body.should have_selector("feed title") - end - - it "should not render projects page via private token" do - logout - - visit dashboard_path(private_token: @user.private_token) - current_path.should == new_user_session_path + context "projects page via private token" do + it "should redirect to login page" do + visit dashboard_path(private_token: user.private_token) + current_path.should == new_user_session_path + end end end end diff --git a/spec/requests/atom/issues_spec.rb b/spec/requests/atom/issues_spec.rb index 468d1b22..c8671979 100644 --- a/spec/requests/atom/issues_spec.rb +++ b/spec/requests/atom/issues_spec.rb @@ -1,40 +1,34 @@ require 'spec_helper' -describe "Issues" do - let(:project) { Factory :project } - - before do - login_as :user - project.add_access(@user, :read, :write) - end - +describe "Issues Feed" do describe "GET /issues" do - before do - @issue = Factory :issue, - author: @user, - assignee: @user, - project: project + let!(:user) { Factory :user } + let!(:project) { Factory :project, owner: user } + let!(:issue) { Factory :issue, author: user, project: project } - visit project_issues_path(project) + before { project.add_access(user, :read, :write) } + + context "when authenticated" do + it "should render atom feed" do + login_with user + visit project_issues_path(project, :atom) + + page.response_headers['Content-Type'].should have_content("application/atom+xml") + page.body.should have_selector("title", text: "#{project.name} issues") + page.body.should have_selector("author email", text: issue.author_email) + page.body.should have_selector("entry summary", text: issue.title) + end end - it "should render atom feed" do - visit project_issues_path(project, :atom) + context "when authenticated via private token" do + it "should render atom feed" do + visit project_issues_path(project, :atom, private_token: user.private_token) - page.response_headers['Content-Type'].should have_content("application/atom+xml") - page.body.should have_selector("title", text: "#{project.name} issues") - page.body.should have_selector("author email", text: @issue.author_email) - page.body.should have_selector("entry summary", text: @issue.title) - end - - it "should render atom feed via private token" do - logout - visit project_issues_path(project, :atom, private_token: @user.private_token) - - page.response_headers['Content-Type'].should have_content("application/atom+xml") - page.body.should have_selector("title", text: "#{project.name} issues") - page.body.should have_selector("author email", text: @issue.author_email) - page.body.should have_selector("entry summary", text: @issue.title) + page.response_headers['Content-Type'].should have_content("application/atom+xml") + page.body.should have_selector("title", text: "#{project.name} issues") + page.body.should have_selector("author email", text: issue.author_email) + page.body.should have_selector("entry summary", text: issue.title) + end end end end From b6f249dc1f4b1867f8f16a23b30f65f4be8e7fd7 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Wed, 12 Sep 2012 05:11:56 -0700 Subject: [PATCH 049/123] make API specs more organized and readable --- spec/requests/api/issues_spec.rb | 10 ++++++---- spec/requests/api/projects_spec.rb | 10 ++++++---- spec/requests/api/users_spec.rb | 10 ++++++---- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 293ea83a..442e9c73 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -9,12 +9,14 @@ describe Gitlab::API do before { project.add_access(user, :read) } describe "GET /issues" do - it "should return authentication error" do - get api("/issues") - response.status.should == 401 + context "when unauthenticated" do + it "should return authentication error" do + get api("/issues") + response.status.should == 401 + end end - describe "authenticated GET /issues" do + context "when authenticated" do it "should return an array of issues" do get api("/issues", user) response.status.should == 200 diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index cc6843cc..9412287f 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -9,12 +9,14 @@ describe Gitlab::API do before { project.add_access(user, :read) } describe "GET /projects" do - it "should return authentication error" do - get api("/projects") - response.status.should == 401 + context "when unauthenticated" do + it "should return authentication error" do + get api("/projects") + response.status.should == 401 + end end - describe "authenticated GET /projects" do + context "when authenticated" do it "should return an array of projects" do get api("/projects", user) response.status.should == 200 diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index d791962a..e25fe134 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -6,12 +6,14 @@ describe Gitlab::API do let(:user) { Factory :user } describe "GET /users" do - it "should return authentication error" do - get api("/users") - response.status.should == 401 + context "when unauthenticated" do + it "should return authentication error" do + get api("/users") + response.status.should == 401 + end end - describe "authenticated GET /users" do + context "when authenticated" do it "should return an array of users" do get api("/users", user) response.status.should == 200 From acc5302c3fea3f07a654e270f06ebf96fec14c5c Mon Sep 17 00:00:00 2001 From: randx Date: Wed, 12 Sep 2012 18:56:44 +0300 Subject: [PATCH 050/123] improve profile layout after omniauth changes --- app/assets/stylesheets/common.scss | 14 ++++++ .../stylesheets/gitlab_bootstrap/blocks.scss | 4 ++ app/helpers/profile_helper.rb | 7 +++ app/views/profile/password.html.haml | 46 +++++++++---------- app/views/profile/show.html.haml | 39 ++++++++-------- config/gitlab.yml.example | 4 +- 6 files changed, 67 insertions(+), 47 deletions(-) create mode 100644 app/helpers/profile_helper.rb diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index ed71a42e..ab3d44d8 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -689,3 +689,17 @@ 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; + @include border-radius(5px); + } + } +} diff --git a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss index e0ae8db7..ae66bd20 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss @@ -65,6 +65,10 @@ border-color: #CCC; @include solid_shade; + &.white { + background:#fff; + } + ul { margin:0; } diff --git a/app/helpers/profile_helper.rb b/app/helpers/profile_helper.rb new file mode 100644 index 00000000..80d67009 --- /dev/null +++ b/app/helpers/profile_helper.rb @@ -0,0 +1,7 @@ +module ProfileHelper + def oauth_active_class provider + if current_user.provider == provider.to_s + 'active' + end + end +end diff --git a/app/views/profile/password.html.haml b/app/views/profile/password.html.haml index bf58e2ae..805429e3 100644 --- a/app/views/profile/password.html.haml +++ b/app/views/profile/password.html.haml @@ -1,31 +1,29 @@ +- if Gitlab.config.omniauth_enabled? + %h3.page_title Accounts + %hr + %p.hint Tip: Click on icon to activate sigin with one of the following services + .oauth_select_holder + - User.omniauth_providers.each do |provider| + %span{class: oauth_active_class(provider) } + = link_to authbutton(provider, 32), omniauth_authorize_path(User, provider) + +.clearfix.prepend-top-20 %h3.page_title Password %hr = form_for @user, url: profile_password_path, method: :put do |f| - .row - .span7 - .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 + %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 - - - if Gitlab.config.omniauth_enabled? - .span5.right - .alert.alert-info - %strong Tip: Use one of the following sites to login - %ul.unstyled - - User.omniauth_providers.each do |provider| - %li= link_to authbutton(provider), | - omniauth_authorize_path(User, provider) | + .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/show.html.haml b/app/views/profile/show.html.haml index 8369da4c..5ac84122 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 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_password_path + + %hr + .row + .span7 .control-group = f.label :skype, class: "control-label" .controls= f.text_field :skype, class: "input-xlarge" @@ -44,23 +59,7 @@ = 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 - - -unless Gitlab.config.disable_gravatar? - %p.alert.alert-info - %strong Tip: - You can change your avatar at gravatar.com - - - @user.provider = 'twitter' - - if Gitlab.config.omniauth_enabled? && @user.provider? - .ui-box - .ui-box-body - %h4 - Omniauth Providers: - = link_to "Change", profile_password_path, class: "btn small right" - You can login through #{@user.provider.titleize}! - = authbutton(@user.provider, 32) - - .ui-box + .ui-box.white .ui-box-body %h4 Personal projects: @@ -71,7 +70,7 @@ .progress .bar{style: "width: #{current_user.projects_limit_percent}%;"} - .ui-box + .ui-box.white .ui-box-body %h4 SSH public keys: diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 80d95b26..28323484 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -26,8 +26,6 @@ app: # disable_gravatar: true # default: false - Disable user avatars from Gravatar.com - - # # 2. Auth settings # ========================== @@ -44,7 +42,7 @@ ldap: omniauth: # Enable ability for users # to login via twitter, google .. - enabled: true + enabled: false # IMPORTANT! # It allows user to login without having user account From 9329dfbfc59325196fc98bcb15bd47adf8121013 Mon Sep 17 00:00:00 2001 From: randx Date: Wed, 12 Sep 2012 19:01:52 +0300 Subject: [PATCH 051/123] Show inline providers icons on login page --- app/views/devise/sessions/new.html.haml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index e217cba6..07ecf70b 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -16,7 +16,6 @@ = render :partial => "devise/shared/links" - if devise_mapping.omniauthable? %hr/ - %ul.unstyled - - resource_class.omniauth_providers.each do |provider| - %li - = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider) + - resource_class.omniauth_providers.each do |provider| + %span + = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider) From 4782163c7acd3dc972675df4d6378244a8970450 Mon Sep 17 00:00:00 2001 From: randx Date: Wed, 12 Sep 2012 19:06:32 +0300 Subject: [PATCH 052/123] Use default tw thubmnails --- app/assets/stylesheets/common.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index ab3d44d8..69a3d743 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -660,7 +660,7 @@ li.note { margin-right:40px; .prev { - @extend .borders; + @extend .thumbnail; height:120px; width:175px; margin-bottom:10px; From 0d77209ea0f13184a8140efeaafa52bc916ec71f Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 12 Sep 2012 18:11:59 -0400 Subject: [PATCH 053/123] Be more resilient in the case of missing omniauth settings Should no longer freak out when omniauth settings aren't present in gitlab.yml. People who aren't using it shouldn't even have to put a 'false' entry in their config for it (and probably wouldn't, after an upgrade). --- config/initializers/1_settings.rb | 8 ++++---- lib/gitlab/auth.rb | 6 +++--- spec/lib/auth_spec.rb | 4 +++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 326f5af2..7a7ca43f 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -121,19 +121,19 @@ class Settings < Settingslogic end def ldap_enabled? - ldap['enabled'] - rescue + ldap && ldap['enabled'] + rescue Settingslogic::MissingSetting false end def omniauth_enabled? omniauth && omniauth['enabled'] - rescue + rescue Settingslogic::MissingSetting false end def omniauth_providers - omniauth['providers'] || [] + (omniauth_enabled? && omniauth['providers']) || [] end def disable_gravatar? diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index ef058ff5..90bd5d74 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -17,7 +17,7 @@ module Gitlab end end - def create_from_omniauth auth, ldap = false + def create_from_omniauth(auth, ldap = false) provider = auth.provider uid = auth.info.uid || auth.uid name = auth.info.name.force_encoding("utf-8") @@ -39,7 +39,7 @@ module Gitlab password_confirmation: password, projects_limit: Gitlab.config.default_projects_limit, ) - if Gitlab.config.omniauth.block_auto_created_users && !ldap + if Gitlab.config.omniauth['block_auto_created_users'] && !ldap @user.blocked = true end @user.save! @@ -52,7 +52,7 @@ module Gitlab if @user = User.find_by_provider_and_extern_uid(provider, uid) @user else - if Gitlab.config.omniauth.allow_single_sign_on + if Gitlab.config.omniauth['allow_single_sign_on'] @user = create_from_omniauth(auth) @user end diff --git a/spec/lib/auth_spec.rb b/spec/lib/auth_spec.rb index 5faf1307..1e03bc59 100644 --- a/spec/lib/auth_spec.rb +++ b/spec/lib/auth_spec.rb @@ -4,6 +4,8 @@ describe Gitlab::Auth do let(:gl_auth) { Gitlab::Auth.new } before do + Gitlab.config.stub(omniauth: {}) + @info = mock( uid: '12djsak321', name: 'John', @@ -64,7 +66,7 @@ describe Gitlab::Auth do end it "should create user if single_sing_on"do - Gitlab.config.omniauth.stub allow_single_sign_on: true + Gitlab.config.omniauth['allow_single_sign_on'] = true User.stub find_by_provider_and_extern_uid: nil gl_auth.should_receive :create_from_omniauth gl_auth.find_or_new_for_omniauth(@auth) From d993f666423744d213d7cce063b48e71fa751d43 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 13 Sep 2012 15:20:00 -0400 Subject: [PATCH 054/123] Fix HTML entities being parsed in GFM Also fixes the spec so that it actually tests the thing it says it's testing. Hooray! Closes #1308 --- lib/gitlab/markdown.rb | 22 +++++++++++++++------ spec/helpers/gitlab_markdown_helper_spec.rb | 1 + 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 4fc0c392..0a467a8d 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -26,13 +26,13 @@ module Gitlab # => "\":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 @@ -84,6 +84,13 @@ module Gitlab # # Returns parsed text def parse(text) + 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 || '' @@ -91,13 +98,18 @@ module Gitlab 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 end - end if @project + end + end + def parse_emoji(text) # parse emoji text.gsub!(EMOJI_PATTERN) do |match| if valid_emoji?($2) @@ -106,8 +118,6 @@ module Gitlab match end end - - text end # Private: Checks if an emoji icon exists in the image asset directory diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index 4dd3802a..0af33142 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -31,6 +31,7 @@ describe GitlabMarkdownHelper do end it "should not touch HTML entities" do + @project.issues.stub(:where).with(id: '39').and_return([issue]) actual = expected = "We'll accept good pull requests." gfm(actual).should == expected end From 795cc9b7161b3c2e580075a88d7b53ef95e3f883 Mon Sep 17 00:00:00 2001 From: Peter Gonda Date: Fri, 14 Sep 2012 15:57:25 +0200 Subject: [PATCH 055/123] Repaired Get patch --- app/controllers/commits_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/commits_controller.rb b/app/controllers/commits_controller.rb index 4ab40c30..6d3f1aea 100644 --- a/app/controllers/commits_controller.rb +++ b/app/controllers/commits_controller.rb @@ -64,7 +64,7 @@ class CommitsController < ApplicationController @commit.to_patch, type: "text/plain", disposition: 'attachment', - filename: "#{@commit.id.patch}" + filename: "#{@commit.id}.patch" ) end From dc37c8aaae29f2340ba3fd0bcda08c937010abde Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 14 Sep 2012 19:13:25 +0300 Subject: [PATCH 056/123] Refactored profile area --- app/assets/stylesheets/common.scss | 7 +++ app/assets/stylesheets/main.scss | 5 ++ app/assets/stylesheets/sections/profile.scss | 8 +++ app/controllers/profile_controller.rb | 8 ++- app/helpers/application_helper.rb | 3 +- app/views/layouts/profile.html.haml | 10 ++-- app/views/profile/account.html.haml | 57 +++++++++++++++++++ app/views/profile/history.html.haml | 5 ++ app/views/profile/password.html.haml | 29 ---------- app/views/profile/show.html.haml | 4 +- app/views/profile/token.html.haml | 23 -------- config/routes.rb | 3 +- features/profile/profile.feature | 2 +- features/steps/shared/paths.rb | 4 +- spec/requests/security/profile_access_spec.rb | 4 +- 15 files changed, 104 insertions(+), 68 deletions(-) create mode 100644 app/assets/stylesheets/sections/profile.scss create mode 100644 app/views/profile/account.html.haml create mode 100644 app/views/profile/history.html.haml delete mode 100644 app/views/profile/password.html.haml delete mode 100644 app/views/profile/token.html.haml diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 69a3d743..fda8d54c 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -699,7 +699,14 @@ li.note { .active { img { border:1px solid #ccc; + background:$hover; @include border-radius(5px); } } } + +.btn-build-token { + float: left; + padding: 6px 20px; + margin-right: 12px; +} diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss index 9a6d4456..75001d3a 100644 --- a/app/assets/stylesheets/main.scss +++ b/app/assets/stylesheets/main.scss @@ -160,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/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/controllers/profile_controller.rb b/app/controllers/profile_controller.rb index a95a3310..ba68af2e 100644 --- a/app/controllers/profile_controller.rb +++ b/app/controllers/profile_controller.rb @@ -32,10 +32,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/helpers/application_helper.rb b/app/helpers/application_helper.rb index fb1393e2..3e435840 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -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" diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml index 810b346f..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 "Authentication", 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/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 805429e3..00000000 --- a/app/views/profile/password.html.haml +++ /dev/null @@ -1,29 +0,0 @@ -- if Gitlab.config.omniauth_enabled? - %h3.page_title Accounts - %hr - %p.hint Tip: Click on icon to activate sigin with one of the following services - .oauth_select_holder - - User.omniauth_providers.each do |provider| - %span{class: oauth_active_class(provider) } - = link_to authbutton(provider, 32), omniauth_authorize_path(User, provider) - -.clearfix.prepend-top-20 -%h3.page_title Password -%hr - -= form_for @user, url: profile_password_path, method: :put do |f| - %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/show.html.haml b/app/views/profile/show.html.haml index 5ac84122..7b625291 100644 --- a/app/views/profile/show.html.haml +++ b/app/views/profile/show.html.haml @@ -33,13 +33,13 @@ %ul -unless Gitlab.config.disable_gravatar? %li - %p.hint You can change your avatar at gravatar.com + %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_password_path + = link_to "click here to change", profile_account_path %hr .row 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/config/routes.rb b/config/routes.rb index ed5eac0d..84a0c6ab 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -63,7 +63,8 @@ Gitlab::Application.routes.draw do # # Profile Area # - get "profile/password", :to => "profile#password" + get "profile/account", :to => "profile#account" + get "profile/history", :to => "profile#history" put "profile/password", :to => "profile#password_update" get "profile/token", :to => "profile#token" put "profile/reset_private_token", :to => "profile#reset_private_token" diff --git a/features/profile/profile.feature b/features/profile/profile.feature index f4b2f198..03cb7a13 100644 --- a/features/profile/profile.feature +++ b/features/profile/profile.feature @@ -12,7 +12,7 @@ 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 diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index 05ae88e6..b0028f9c 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -21,8 +21,8 @@ module SharedPaths visit profile_path end - Given 'I visit profile password page' do - visit profile_password_path + Given 'I visit profile account page' do + visit profile_account_path end Given 'I visit profile token page' do diff --git a/spec/requests/security/profile_access_spec.rb b/spec/requests/security/profile_access_spec.rb index 9f6fe6a2..69c1c29c 100644 --- a/spec/requests/security/profile_access_spec.rb +++ b/spec/requests/security/profile_access_spec.rb @@ -28,8 +28,8 @@ describe "Users Security" do it { should be_denied_for :visitor } end - describe "GET /profile/password" do - subject { profile_password_path } + describe "GET /profile/account" do + subject { profile_account_path } it { should be_allowed_for @u1 } it { should be_allowed_for :admin } From 759fb518eb28ca59913f1c897b3cc056693709ca Mon Sep 17 00:00:00 2001 From: randx Date: Fri, 14 Sep 2012 18:46:40 +0300 Subject: [PATCH 057/123] fix event issue when event for left project + project removed --- app/models/event.rb | 36 +++++++++++-------- .../_event_membership_changed.html.haml | 2 +- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/app/models/event.rb b/app/models/event.rb index 308ffd63..b11b21bd 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -35,13 +35,21 @@ class Event < ActiveRecord::Base end # Next events currently enabled for system - # - push + # - push # - new issue # - merge request def allowed? push? || issue? || merge_request? || membership_changed? end + def project_name + if project + project.name + else + "(deleted)" + end + end + def push? action == self.class::Pushed && valid_push? end @@ -58,31 +66,31 @@ class Event < ActiveRecord::Base action == self.class::Reopened end - def issue? + def issue? target_type == "Issue" end - def merge_request? + def merge_request? target_type == "MergeRequest" end - def new_issue? - target_type == "Issue" && + def new_issue? + target_type == "Issue" && action == Created end - def new_merge_request? - target_type == "MergeRequest" && + def new_merge_request? + target_type == "MergeRequest" && action == Created end - def changed_merge_request? - target_type == "MergeRequest" && + def changed_merge_request? + target_type == "MergeRequest" && [Closed, Reopened].include?(action) end - def changed_issue? - target_type == "Issue" && + def changed_issue? + target_type == "Issue" && [Closed, Reopened].include?(action) end @@ -98,7 +106,7 @@ class Event < ActiveRecord::Base joined? || left? end - def issue + def issue target if target_type == "Issue" end @@ -106,7 +114,7 @@ class Event < ActiveRecord::Base target if target_type == "MergeRequest" end - def author + def author @author ||= User.find(author_id) end @@ -119,7 +127,7 @@ class Event < ActiveRecord::Base 'joined' elsif left? 'left' - else + else "opened" end end diff --git a/app/views/events/_event_membership_changed.html.haml b/app/views/events/_event_membership_changed.html.haml index b079c138..464f24b3 100644 --- a/app/views/events/_event_membership_changed.html.haml +++ b/app/views/events/_event_membership_changed.html.haml @@ -2,7 +2,7 @@ %strong #{event.author_name} %span.event_label{class: event.action_name}= event.action_name project -%strong= link_to event.project.name, event.project +%strong= link_to event.project_name, event.project %span.cgray = time_ago_in_words(event.created_at) ago. From 0d66cf2a38540056b6400c526e62ccc0cbc3144d Mon Sep 17 00:00:00 2001 From: randx Date: Fri, 14 Sep 2012 18:58:16 +0300 Subject: [PATCH 058/123] Fixed token feature --- features/profile/profile.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/profile/profile.feature b/features/profile/profile.feature index 03cb7a13..134cabb5 100644 --- a/features/profile/profile.feature +++ b/features/profile/profile.feature @@ -17,6 +17,6 @@ Feature: Profile 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 From 8b6dba749a80fbdf94f1495dda8cf3cdad61a28b Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Thu, 13 Sep 2012 02:12:44 +0200 Subject: [PATCH 059/123] Reorder notes view elements --- app/assets/javascripts/note.js | 8 ++++---- app/assets/stylesheets/sections/notes.scss | 6 +++++- app/views/notes/_notes.html.haml | 9 ++++----- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/note.js b/app/assets/javascripts/note.js index 79ab086b..47b0e0f5 100644 --- a/app/assets/javascripts/note.js +++ b/app/assets/javascripts/note.js @@ -106,8 +106,8 @@ var NoteList = { type: "GET", url: this.notes_path, data: "?" + this.target_params, - complete: function(){ $('.status').removeClass("loading")}, - beforeSend: function() { $('.status').addClass("loading") }, + complete: function(){ $('.notes-status').removeClass("loading")}, + beforeSend: function() { $('.notes-status').addClass("loading") }, dataType: "script"}); }, @@ -136,8 +136,8 @@ var NoteList = { 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") }, + complete: function(){ $('.notes-status').removeClass("loading")}, + beforeSend: function() { $('.notes-status').addClass("loading") }, dataType: "script"}); }, diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 6a965fa4..b2f61d9b 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -10,7 +10,7 @@ padding:0px; } -#new_notes_list li:last-child{ +#notes-list li:last-child { border-bottom:1px solid #aaa; } @@ -71,6 +71,10 @@ } } +.notes-status { + margin: 18px; +} + p.notify_controls input{ margin: 5px; diff --git a/app/views/notes/_notes.html.haml b/app/views/notes/_notes.html.haml index e692e746..e5b1ea72 100644 --- a/app/views/notes/_notes.html.haml +++ b/app/views/notes/_notes.html.haml @@ -1,10 +1,9 @@ +%ul#notes-list +%ul#new_notes_list +.notes-status + - if can? current_user, :write_note, @project = render "notes/form" -.clear -%hr -%ul#new_notes_list -%ul#notes-list -.status :javascript From 6ffec9a298dd90275ec6b17d1e11554bd31b9f2c Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Thu, 13 Sep 2012 15:43:16 +0200 Subject: [PATCH 060/123] Update Note to load notes in the right order --- app/contexts/notes/load_context.rb | 23 ++++++++++++----------- app/models/note.rb | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/app/contexts/notes/load_context.rb b/app/contexts/notes/load_context.rb index c89a7d19..c026fc50 100644 --- a/app/contexts/notes/load_context.rb +++ b/app/contexts/notes/load_context.rb @@ -8,24 +8,25 @@ module Notes @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").limit(50) when "wiki" - then project.wikis.reverse.map {|w| w.notes.fresh }.flatten[0..20] + project.wikis.reverse.map {|w| w.notes.fresh }.flatten[0..20] end @notes = if last_id - @notes.where("id > ?", last_id) + @notes.where("id < ?", last_id) elsif first_id - @notes.where("id < ?", first_id) + @notes.where("id > ?", first_id) else @notes end diff --git a/app/models/note.rb b/app/models/note.rb index 4c46c7df..9aad8949 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -36,7 +36,7 @@ class Note < ActiveRecord::Base scope :today, where("created_at >= :date", date: Date.today) scope :last_week, where("created_at >= :date", date: (Date.today - 7.days)) scope :since, lambda { |day| where("created_at >= :date", date: (day)) } - scope :fresh, order("created_at DESC") + scope :fresh, order("created_at ASC") scope :inc_author_project, includes(:project, :author) scope :inc_author, includes(:author) From 14164017533388dc2a0d0f43e05ee84badbf2223 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Thu, 13 Sep 2012 19:55:57 +0200 Subject: [PATCH 061/123] Fix markup --- app/assets/stylesheets/sections/notes.scss | 2 +- app/views/notes/_notes.html.haml | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index b2f61d9b..8db88930 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -3,7 +3,7 @@ * */ #notes-list, -#new_notes_list { +#new-notes-list { display:block; list-style:none; margin:0px; diff --git a/app/views/notes/_notes.html.haml b/app/views/notes/_notes.html.haml index e5b1ea72..14e1e84b 100644 --- a/app/views/notes/_notes.html.haml +++ b/app/views/notes/_notes.html.haml @@ -1,11 +1,10 @@ %ul#notes-list -%ul#new_notes_list +%ul#new-notes-list .notes-status - if can? current_user, :write_note, @project = render "notes/form" - :javascript $(function(){ NoteList.init("#{tid}", "#{tt}", "#{project_notes_path(@project)}"); From e802d00996d6948e29f085d4de9409423e0d91a4 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 16:52:24 +0200 Subject: [PATCH 062/123] Completely redo loading of notes with JS --- app/assets/javascripts/note.js | 199 ++++++++++++++----------- app/contexts/notes/load_context.rb | 9 +- app/helpers/notes_helper.rb | 9 ++ app/views/notes/_create_common.js.haml | 3 +- app/views/notes/_load.js.haml | 14 +- 5 files changed, 134 insertions(+), 100 deletions(-) create mode 100644 app/helpers/notes_helper.rb diff --git a/app/assets/javascripts/note.js b/app/assets/javascripts/note.js index 47b0e0f5..ccc84ac9 100644 --- a/app/assets/javascripts/note.js +++ b/app/assets/javascripts/note.js @@ -4,9 +4,8 @@ var NoteList = { target_params: null, target_id: 0, target_type: null, - first_id: 0, - last_id: 0, - disable:false, + bottom_id: 0, + loading_more_disabled: false, init: function(tid, tt, path) { @@ -15,26 +14,23 @@ var NoteList = { this.target_type = tt; this.target_params = "&target_type=" + this.target_type + "&target_id=" + this.target_id; - // get notes + // get initial set of notes this.getContent(); - // get new notes every n seconds - this.initRefresh(); - $('.delete-note').live('ajax:success', function() { $(this).closest('li').fadeOut(); }); - $(".note-form-holder").live("ajax:before", function(){ + $(".note-form-holder").on("ajax:before", function(){ $(".submit_note").disable() }) - $(".note-form-holder").live("ajax:complete", function(){ + $(".note-form-holder").on("ajax:complete", function(){ $(".submit_note").enable() }) disableButtonIfEmptyField(".note-text", ".submit_note"); - $(".note-text").live("focus", function(){ + $(".note-text").on("focus", function(){ $(this).css("height", "80px"); $('.note_advanced_opts').show(); }); @@ -44,64 +40,20 @@ var NoteList = { 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 + * Handle loading the initial set of notes. + * And set up loading more notes when scrolling to the bottom of the page. */ - 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 + * Gets an inital set of notes. */ - - - getContent: - function() { + getContent: + function() { $.ajax({ type: "GET", url: this.notes_path, @@ -111,10 +63,13 @@ var NoteList = { dataType: "script"}); }, + /** + * Called in response to getContent(). + * Replaces the content of #notes-list with the given html. + */ setContent: - function(fid, lid, html) { - this.last_id = lid; - this.first_id = fid; + function(last_id, html) { + this.bottom_id = last_id; $("#notes-list").html(html); // Init infinite scrolling @@ -123,54 +78,126 @@ var NoteList = { /** - * 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' + * 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. */ - getOld: + + + /** + * 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: "first_id=" + this.first_id + this.target_params, + data: "loading_more=1&after_id=" + this.bottom_id + this.target_params, complete: function(){ $('.notes-status').removeClass("loading")}, beforeSend: function() { $('.notes-status').addClass("loading") }, dataType: "script"}); }, - append: + /** + * Called in response to getMore(). + * Append notes to #notes-list. + */ + appendMoreNotes: function(id, html) { - if(this.first_id == id) { - this.disable = true; - } else { - this.first_id = id; + if(id != this.bottom_id) { + this.bottom_id = id; $("#notes-list").append(html); } }, - initLoadMore: + /** + * Called in response to getMore(). + * Disables loading more notes when scrolling to the bottom of the page. + * Initalizes refreshing new notes. + */ + finishedLoadingMore: function() { - $(document).endlessScroll({ - bottomPixels: 400, - fireDelay: 1000, - fireOnce:true, - ceaseFire: function() { - return NoteList.disable; - }, - callback: function(i) { - NoteList.getOld(); + this.loading_more_disabled = true; + + // from now on only get new notes + this.initRefreshNew(); + }, + + + /** + * 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 (i.e. all notes after ). + */ + getNew: + function() { + $.ajax({ + type: "GET", + url: this.notes_path, + data: "loading_new=1&after_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); + }, + + /** + * Adds a single note to #new-notes-list. + */ + appendNewNote: + function(id, html) { + if(id != this.bottom_id) { + $("#new-notes-list").append(html); } - }); } }; -var PerLineNotes = { +var PerLineNotes = { init: function() { - $(".line_note_link, .line_note_reply_link").live("click", function(e) { + $(".line_note_link, .line_note_reply_link").on("click", function(e) { var form = $(".per_line_form"); $(this).closest("tr").after(form); form.find("#note_line_code").val($(this).attr("line_code")); diff --git a/app/contexts/notes/load_context.rb b/app/contexts/notes/load_context.rb index c026fc50..c2d7644b 100644 --- a/app/contexts/notes/load_context.rb +++ b/app/contexts/notes/load_context.rb @@ -3,8 +3,7 @@ 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] @notes = case target_type @@ -23,10 +22,8 @@ module Notes project.wikis.reverse.map {|w| w.notes.fresh }.flatten[0..20] end - @notes = if last_id - @notes.where("id < ?", last_id) - elsif first_id - @notes.where("id > ?", first_id) + @notes = if after_id + @notes.where("id > ?", after_id) else @notes end diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb new file mode 100644 index 00000000..28701661 --- /dev/null +++ b/app/helpers/notes_helper.rb @@ -0,0 +1,9 @@ +module NotesHelper + def loading_more_notes? + params[:loading_more].present? + end + + def loading_new_notes? + params[:loading_new].present? + end +end diff --git a/app/views/notes/_create_common.js.haml b/app/views/notes/_create_common.js.haml index e80eccb1..ce678585 100644 --- a/app/views/notes/_create_common.js.haml +++ b/app/views/notes/_create_common.js.haml @@ -5,7 +5,8 @@ $('.note-form-holder #preview-link').text('Preview'); $('.note-form-holder #preview-note').hide(); $('.note-form-holder').show(); - NoteList.prepend(#{note.id}, "#{escape_javascript(render partial: "notes/show", locals: {note: note})}"); + NoteList.appendNewNote(#{note.id}, "#{escape_javascript(render "notes/show", note: note)}"); + - else :plain $(".note-form-holder").replaceWith("#{escape_javascript(render('form'))}"); diff --git a/app/views/notes/_load.js.haml b/app/views/notes/_load.js.haml index c16a699a..8c735476 100644 --- a/app/views/notes/_load.js.haml +++ b/app/views/notes/_load.js.haml @@ -1,17 +1,17 @@ - unless @notes.blank? - - if params[:last_id] + - if loading_more_notes? :plain - NoteList.replace("#{escape_javascript(render(partial: 'notes/notes_list'))}"); + NoteList.appendMoreNotes(#{@notes.last.id}, "#{escape_javascript(render 'notes/notes_list')}"); - - elsif params[:first_id] + - elsif loading_new_notes? :plain - NoteList.append(#{@notes.last.id}, "#{escape_javascript(render(partial: 'notes/notes_list'))}"); + NoteList.replaceNewNotes("#{escape_javascript(render 'notes/notes_list')}"); - else :plain - NoteList.setContent(#{@notes.last.id}, #{@notes.first.id}, "#{escape_javascript(render(partial: 'notes/notes_list'))}"); + NoteList.setContent(#{@notes.last.id}, "#{escape_javascript(render 'notes/notes_list')}"); - else - - if params[:first_id] + - if loading_more_notes? :plain - NoteList.append(#{params[:first_id]}, ""); + NoteList.finishedLoadingMore(); From 20e009a40a4fa5d7e5517833e14c16b32b461720 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 01:21:39 +0200 Subject: [PATCH 063/123] Update diff comments order and rendering --- app/views/commits/_text_file.html.haml | 4 ++-- app/views/notes/_create_common.js.haml | 2 +- app/views/notes/_per_line_show.html.haml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/commits/_text_file.html.haml b/app/views/commits/_text_file.html.haml index 0f6210f2..5dc8dbd3 100644 --- a/app/views/commits/_text_file.html.haml +++ b/app/views/commits/_text_file.html.haml @@ -18,9 +18,9 @@ %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw "#{line}  " - if @comments_allowed - - comments = @line_notes.select { |n| n.line_code == line_code }.sort_by(&:created_at).reverse + - comments = @line_notes.select { |n| n.line_code == line_code }.sort_by(&:created_at) - unless comments.empty? - comments.each_with_index do |note, i| - = render "notes/reply_button", line_code: line_code if i.zero? = render "notes/per_line_show", note: note - @line_notes.reject!{ |n| n == note } + = render "notes/reply_button", line_code: line_code diff --git a/app/views/notes/_create_common.js.haml b/app/views/notes/_create_common.js.haml index ce678585..0a00bd40 100644 --- a/app/views/notes/_create_common.js.haml +++ b/app/views/notes/_create_common.js.haml @@ -9,5 +9,5 @@ - else :plain - $(".note-form-holder").replaceWith("#{escape_javascript(render('form'))}"); + $(".note-form-holder").replaceWith("#{escape_javascript(render 'form')}"); diff --git a/app/views/notes/_per_line_show.html.haml b/app/views/notes/_per_line_show.html.haml index cf1769c0..9d5a31a7 100644 --- a/app/views/notes/_per_line_show.html.haml +++ b/app/views/notes/_per_line_show.html.haml @@ -1,5 +1,5 @@ %tr.line_notes_row %td{colspan: 3} %ul - = render partial: "notes/show", locals: {note: note} + = render "notes/show", note: note From 653f7ec4fb57f84f471c8f2078c7534b1c085cc9 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 01:22:09 +0200 Subject: [PATCH 064/123] Update links for inline comments to use data-* attributes --- app/views/commits/_text_file.html.haml | 2 +- app/views/notes/_reply_button.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/commits/_text_file.html.haml b/app/views/commits/_text_file.html.haml index 5dc8dbd3..7a00eb45 100644 --- a/app/views/commits/_text_file.html.haml +++ b/app/views/commits/_text_file.html.haml @@ -13,7 +13,7 @@ %td.old_line = link_to raw(type == "new" ? " " : line_old), "##{line_code}", id: line_code - if @comments_allowed - = link_to "", "#", class: "line_note_link", "line_code" => line_code, title: "Add note for this line" + = link_to "", "#", class: "line_note_link", data: { line_code: line_code }, title: "Add note for this line" %td.new_line= link_to raw(type == "old" ? " " : line_new) , "##{line_code}", id: line_code %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw "#{line}  " diff --git a/app/views/notes/_reply_button.html.haml b/app/views/notes/_reply_button.html.haml index c981fb9f..42c737c7 100644 --- a/app/views/notes/_reply_button.html.haml +++ b/app/views/notes/_reply_button.html.haml @@ -1,4 +1,4 @@ %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" + = link_to "Reply", "#", class: "line_note_reply_link", data: { line_code: line_code }, title: "Add note for this line" From cee230a158e72a973150a17034b58c869f7e9407 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 01:32:55 +0200 Subject: [PATCH 065/123] Update JS for adding and removing diff line notes --- app/assets/javascripts/note.js | 37 +++++++++++++++++++++++++--- app/views/notes/_create_line.js.haml | 19 +++++++++++--- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/note.js b/app/assets/javascripts/note.js index ccc84ac9..7cbf44b9 100644 --- a/app/assets/javascripts/note.js +++ b/app/assets/javascripts/note.js @@ -17,8 +17,9 @@ var NoteList = { // get initial set of notes this.getContent(); - $('.delete-note').live('ajax:success', function() { - $(this).closest('li').fadeOut(); }); + $("#notes-list, #new-notes-list").on("ajax:success", ".delete-note", function() { + $(this).closest('li').fadeOut(); + }); $(".note-form-holder").on("ajax:before", function(){ $(".submit_note").disable() @@ -197,13 +198,41 @@ var NoteList = { var PerLineNotes = { init: function() { - $(".line_note_link, .line_note_reply_link").on("click", function(e) { + /** + * 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).attr("line_code")); + 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/views/notes/_create_line.js.haml b/app/views/notes/_create_line.js.haml index 662909f7..ab862b2f 100644 --- a/app/views/notes/_create_line.js.haml +++ b/app/views/notes/_create_line.js.haml @@ -1,8 +1,19 @@ - if note.valid? :plain + // hide and reset the form $(".per_line_form").hide(); $('.line-note-form-holder 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})}"); + + // 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/reply_button", line_code: note.line_code)}"); + trEl.after("#{escape_javascript(render "notes/per_line_show", note: note)}"); + } else { + // instert new note before reply button + trRpl.before("#{escape_javascript(render "notes/per_line_show", note: note)}"); + } From 61eb650db0eb05ee6436d662927cb963ec157b76 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 04:59:55 +0200 Subject: [PATCH 066/123] Rename 'notes/notes' partial to 'notes/notes_with_form' --- app/views/commits/show.html.haml | 2 +- app/views/issues/show.html.haml | 2 +- app/views/merge_requests/_show.html.haml | 2 +- app/views/merge_requests/show.js.haml | 2 +- .../notes/{_notes.html.haml => _notes_with_form.html.haml} | 0 app/views/projects/wall.html.haml | 2 +- app/views/snippets/show.html.haml | 2 +- app/views/wikis/show.html.haml | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) rename app/views/notes/{_notes.html.haml => _notes_with_form.html.haml} (100%) diff --git a/app/views/commits/show.html.haml b/app/views/commits/show.html.haml index e01f8ea5..d12fff96 100644 --- a/app/views/commits/show.html.haml +++ b/app/views/commits/show.html.haml @@ -1,6 +1,6 @@ = render "commits/commit_box" = render "commits/diffs", diffs: @commit.diffs -= render "notes/notes", tid: @commit.id, tt: "commit" += render "notes/notes_with_form", tid: @commit.id, tt: "commit" = render "notes/per_line_form" diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index 9b1c72a3..0b72a820 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -61,4 +61,4 @@ = markdown @issue.description -.issue_notes#notes= render "notes/notes", tid: @issue.id, tt: "issue" +.issue_notes#notes= render "notes/notes_with_form", tid: @issue.id, tt: "issue" diff --git a/app/views/merge_requests/_show.html.haml b/app/views/merge_requests/_show.html.haml index f1b3fa9f..40b72190 100644 --- a/app/views/merge_requests/_show.html.haml +++ b/app/views/merge_requests/_show.html.haml @@ -16,7 +16,7 @@ Diff .merge_request_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" } - = render("notes/notes", tid: @merge_request.id, tt: "merge_request") + = 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/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/notes/_notes.html.haml b/app/views/notes/_notes_with_form.html.haml similarity index 100% rename from app/views/notes/_notes.html.haml rename to app/views/notes/_notes_with_form.html.haml diff --git a/app/views/projects/wall.html.haml b/app/views/projects/wall.html.haml index 97765d7a..1a07bc3d 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/notes_with_form", tid: nil, tt: "wall" 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/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" From 8fb70d924dbb089fdac89125664e3aa73212d8fc Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 05:00:21 +0200 Subject: [PATCH 067/123] Rename 'notes/create_*' partials --- .../{_create_common.js.haml => _create_common_note.js.haml} | 0 .../{_create_line.js.haml => _create_per_line_note.js.haml} | 0 app/views/notes/create.js.haml | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename app/views/notes/{_create_common.js.haml => _create_common_note.js.haml} (100%) rename app/views/notes/{_create_line.js.haml => _create_per_line_note.js.haml} (100%) diff --git a/app/views/notes/_create_common.js.haml b/app/views/notes/_create_common_note.js.haml similarity index 100% rename from app/views/notes/_create_common.js.haml rename to app/views/notes/_create_common_note.js.haml diff --git a/app/views/notes/_create_line.js.haml b/app/views/notes/_create_per_line_note.js.haml similarity index 100% rename from app/views/notes/_create_line.js.haml rename to app/views/notes/_create_per_line_note.js.haml 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 From 3c02c93f08019a73929de8e812424e581c58c62a Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 05:05:37 +0200 Subject: [PATCH 068/123] Remove 'notes/load' partial --- app/views/notes/_load.js.haml | 17 ----------------- app/views/notes/index.js.haml | 18 +++++++++++++++++- 2 files changed, 17 insertions(+), 18 deletions(-) delete mode 100644 app/views/notes/_load.js.haml diff --git a/app/views/notes/_load.js.haml b/app/views/notes/_load.js.haml deleted file mode 100644 index 8c735476..00000000 --- a/app/views/notes/_load.js.haml +++ /dev/null @@ -1,17 +0,0 @@ -- unless @notes.blank? - - if loading_more_notes? - :plain - NoteList.appendMoreNotes(#{@notes.last.id}, "#{escape_javascript(render 'notes/notes_list')}"); - - - elsif loading_new_notes? - :plain - NoteList.replaceNewNotes("#{escape_javascript(render 'notes/notes_list')}"); - - - else - :plain - NoteList.setContent(#{@notes.last.id}, "#{escape_javascript(render 'notes/notes_list')}"); - -- else - - if loading_more_notes? - :plain - NoteList.finishedLoadingMore(); diff --git a/app/views/notes/index.js.haml b/app/views/notes/index.js.haml index ee31c0b8..8c735476 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_list')}"); + + - elsif loading_new_notes? + :plain + NoteList.replaceNewNotes("#{escape_javascript(render 'notes/notes_list')}"); + + - else + :plain + NoteList.setContent(#{@notes.last.id}, "#{escape_javascript(render 'notes/notes_list')}"); + +- else + - if loading_more_notes? + :plain + NoteList.finishedLoadingMore(); From c02e3f2104d9dbb1bca01935fe7c0dfeacf53baf Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 05:08:40 +0200 Subject: [PATCH 069/123] Rename 'notes/form' partial to 'notes/common_form' --- app/views/notes/{_form.html.haml => _common_form.html.haml} | 0 app/views/notes/_notes_with_form.html.haml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename app/views/notes/{_form.html.haml => _common_form.html.haml} (100%) diff --git a/app/views/notes/_form.html.haml b/app/views/notes/_common_form.html.haml similarity index 100% rename from app/views/notes/_form.html.haml rename to app/views/notes/_common_form.html.haml diff --git a/app/views/notes/_notes_with_form.html.haml b/app/views/notes/_notes_with_form.html.haml index 14e1e84b..53716c1d 100644 --- a/app/views/notes/_notes_with_form.html.haml +++ b/app/views/notes/_notes_with_form.html.haml @@ -3,7 +3,7 @@ .notes-status - if can? current_user, :write_note, @project - = render "notes/form" + = render "notes/common_form" :javascript $(function(){ From 29c71f2fb95ba98513ff96939fd4a602b4a3bd6f Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 05:10:06 +0200 Subject: [PATCH 070/123] Rename 'notes/reply_button' partial to 'notes/per_line_reply_button' --- app/views/commits/_text_file.html.haml | 2 +- app/views/notes/_create_per_line_note.js.haml | 2 +- ..._reply_button.html.haml => _per_line_reply_button.html.haml} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename app/views/notes/{_reply_button.html.haml => _per_line_reply_button.html.haml} (100%) diff --git a/app/views/commits/_text_file.html.haml b/app/views/commits/_text_file.html.haml index 7a00eb45..f7dae301 100644 --- a/app/views/commits/_text_file.html.haml +++ b/app/views/commits/_text_file.html.haml @@ -23,4 +23,4 @@ - comments.each_with_index do |note, i| = render "notes/per_line_show", note: note - @line_notes.reject!{ |n| n == note } - = render "notes/reply_button", line_code: line_code + = render "notes/per_line_reply_button", line_code: line_code diff --git a/app/views/notes/_create_per_line_note.js.haml b/app/views/notes/_create_per_line_note.js.haml index ab862b2f..d7f0a0dc 100644 --- a/app/views/notes/_create_per_line_note.js.haml +++ b/app/views/notes/_create_per_line_note.js.haml @@ -11,7 +11,7 @@ // 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/reply_button", line_code: note.line_code)}"); + trEl.after("#{escape_javascript(render "notes/per_line_reply_button", line_code: note.line_code)}"); trEl.after("#{escape_javascript(render "notes/per_line_show", note: note)}"); } else { // instert new note before reply button diff --git a/app/views/notes/_reply_button.html.haml b/app/views/notes/_per_line_reply_button.html.haml similarity index 100% rename from app/views/notes/_reply_button.html.haml rename to app/views/notes/_per_line_reply_button.html.haml From 4fc66ead4f50f76efb80e119bbedc7514602f57f Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 05:13:26 +0200 Subject: [PATCH 071/123] Rename 'notes/show' partial to 'notes/note' --- app/views/notes/_create_common_note.js.haml | 2 +- app/views/notes/{_show.html.haml => _note.html.haml} | 0 app/views/notes/_notes_list.html.haml | 2 +- app/views/notes/_per_line_show.html.haml | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename app/views/notes/{_show.html.haml => _note.html.haml} (100%) diff --git a/app/views/notes/_create_common_note.js.haml b/app/views/notes/_create_common_note.js.haml index 0a00bd40..bbebc247 100644 --- a/app/views/notes/_create_common_note.js.haml +++ b/app/views/notes/_create_common_note.js.haml @@ -5,7 +5,7 @@ $('.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/show", note: note)}"); + NoteList.appendNewNote(#{note.id}, "#{escape_javascript(render "notes/note", note: note)}"); - else :plain diff --git a/app/views/notes/_show.html.haml b/app/views/notes/_note.html.haml similarity index 100% rename from app/views/notes/_show.html.haml rename to app/views/notes/_note.html.haml diff --git a/app/views/notes/_notes_list.html.haml b/app/views/notes/_notes_list.html.haml index 5673988d..e2c4bedc 100644 --- a/app/views/notes/_notes_list.html.haml +++ b/app/views/notes/_notes_list.html.haml @@ -1,4 +1,4 @@ - @notes.each do |note| - next unless note.author - = render partial: "notes/show", locals: {note: note} + = render "notes/note", note: note diff --git a/app/views/notes/_per_line_show.html.haml b/app/views/notes/_per_line_show.html.haml index 9d5a31a7..28bcd6e0 100644 --- a/app/views/notes/_per_line_show.html.haml +++ b/app/views/notes/_per_line_show.html.haml @@ -1,5 +1,5 @@ %tr.line_notes_row %td{colspan: 3} %ul - = render "notes/show", note: note + = render "notes/note", note: note From dd1b3177c999560818e8bbfb549630234f6ec9f0 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 05:19:38 +0200 Subject: [PATCH 072/123] Renamed 'notes/notes_list' partial to 'notes/notes' --- app/views/notes/{_notes_list.html.haml => _notes.html.haml} | 2 +- app/views/notes/index.js.haml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename app/views/notes/{_notes_list.html.haml => _notes.html.haml} (59%) diff --git a/app/views/notes/_notes_list.html.haml b/app/views/notes/_notes.html.haml similarity index 59% rename from app/views/notes/_notes_list.html.haml rename to app/views/notes/_notes.html.haml index e2c4bedc..adb5dfcb 100644 --- a/app/views/notes/_notes_list.html.haml +++ b/app/views/notes/_notes.html.haml @@ -1,4 +1,4 @@ - @notes.each do |note| - next unless note.author - = render "notes/note", note: note + = render "note", note: note diff --git a/app/views/notes/index.js.haml b/app/views/notes/index.js.haml index 8c735476..3d6859eb 100644 --- a/app/views/notes/index.js.haml +++ b/app/views/notes/index.js.haml @@ -1,15 +1,15 @@ - unless @notes.blank? - if loading_more_notes? :plain - NoteList.appendMoreNotes(#{@notes.last.id}, "#{escape_javascript(render 'notes/notes_list')}"); + NoteList.appendMoreNotes(#{@notes.last.id}, "#{escape_javascript(render 'notes/notes')}"); - elsif loading_new_notes? :plain - NoteList.replaceNewNotes("#{escape_javascript(render 'notes/notes_list')}"); + NoteList.replaceNewNotes("#{escape_javascript(render 'notes/notes')}"); - else :plain - NoteList.setContent(#{@notes.last.id}, "#{escape_javascript(render 'notes/notes_list')}"); + NoteList.setContent(#{@notes.last.id}, "#{escape_javascript(render 'notes/notes')}"); - else - if loading_more_notes? From c6d71b7b8e5e8dc22da9b8aab392196d1987fd68 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 05:21:58 +0200 Subject: [PATCH 073/123] Rename 'notes/per_line_show' partial to 'notes/per_line_note' --- app/views/commits/_text_file.html.haml | 2 +- app/views/notes/_create_per_line_note.js.haml | 4 ++-- .../{_per_line_show.html.haml => _per_line_note.html.haml} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename app/views/notes/{_per_line_show.html.haml => _per_line_note.html.haml} (100%) diff --git a/app/views/commits/_text_file.html.haml b/app/views/commits/_text_file.html.haml index f7dae301..7626a015 100644 --- a/app/views/commits/_text_file.html.haml +++ b/app/views/commits/_text_file.html.haml @@ -21,6 +21,6 @@ - comments = @line_notes.select { |n| n.line_code == line_code }.sort_by(&:created_at) - unless comments.empty? - comments.each_with_index do |note, i| - = render "notes/per_line_show", note: note + = render "notes/per_line_note", note: note - @line_notes.reject!{ |n| n == note } = render "notes/per_line_reply_button", line_code: line_code diff --git a/app/views/notes/_create_per_line_note.js.haml b/app/views/notes/_create_per_line_note.js.haml index d7f0a0dc..180960e3 100644 --- a/app/views/notes/_create_per_line_note.js.haml +++ b/app/views/notes/_create_per_line_note.js.haml @@ -12,8 +12,8 @@ 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_show", note: note)}"); + 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_show", note: note)}"); + trRpl.before("#{escape_javascript(render "notes/per_line_note", note: note)}"); } diff --git a/app/views/notes/_per_line_show.html.haml b/app/views/notes/_per_line_note.html.haml similarity index 100% rename from app/views/notes/_per_line_show.html.haml rename to app/views/notes/_per_line_note.html.haml From a3dbd990682f5f39d9c3e58858faf85b9b0a6179 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 17:02:09 +0200 Subject: [PATCH 074/123] Extract 'notes/per_line_note_link' partial --- app/views/commits/_text_file.html.haml | 2 +- app/views/notes/_per_line_note_link.html.haml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 app/views/notes/_per_line_note_link.html.haml diff --git a/app/views/commits/_text_file.html.haml b/app/views/commits/_text_file.html.haml index 7626a015..22d2b9ed 100644 --- a/app/views/commits/_text_file.html.haml +++ b/app/views/commits/_text_file.html.haml @@ -13,7 +13,7 @@ %td.old_line = link_to raw(type == "new" ? " " : line_old), "##{line_code}", id: line_code - if @comments_allowed - = link_to "", "#", class: "line_note_link", data: { line_code: line_code }, title: "Add note for this line" + = render "notes/per_line_note_link", line_code: line_code %td.new_line= link_to raw(type == "old" ? " " : line_new) , "##{line_code}", id: line_code %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw "#{line}  " 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" From e1ca155c95a41a9adfe984a3e3ba5c777c61acd8 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 16:57:08 +0200 Subject: [PATCH 075/123] Extract 'notes/per_line_notes_with_reply' partial --- app/views/commits/_text_file.html.haml | 5 +---- app/views/notes/_per_line_notes_with_reply.html.haml | 3 +++ 2 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 app/views/notes/_per_line_notes_with_reply.html.haml diff --git a/app/views/commits/_text_file.html.haml b/app/views/commits/_text_file.html.haml index 22d2b9ed..9f5b5345 100644 --- a/app/views/commits/_text_file.html.haml +++ b/app/views/commits/_text_file.html.haml @@ -20,7 +20,4 @@ - if @comments_allowed - comments = @line_notes.select { |n| n.line_code == line_code }.sort_by(&:created_at) - unless comments.empty? - - comments.each_with_index do |note, i| - = render "notes/per_line_note", note: note - - @line_notes.reject!{ |n| n == note } - = render "notes/per_line_reply_button", line_code: line_code + = render "notes/per_line_notes_with_reply", notes: comments 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 From e63d7b6029142d100adca03e11ba0e33d9c2981c Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 05:56:12 +0200 Subject: [PATCH 076/123] Rename note.js to notes.js --- app/assets/javascripts/{note.js => notes.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/assets/javascripts/{note.js => notes.js} (100%) diff --git a/app/assets/javascripts/note.js b/app/assets/javascripts/notes.js similarity index 100% rename from app/assets/javascripts/note.js rename to app/assets/javascripts/notes.js From 7563abbe49fc16280877be89342d552e0609d57c Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 17:00:48 +0200 Subject: [PATCH 077/123] Add 'notes/reversed_notes_with_form' partial --- app/assets/stylesheets/sections/notes.scss | 14 ++++++++++++-- .../notes/_reversed_notes_with_form.html.haml | 11 +++++++++++ app/views/projects/wall.html.haml | 2 +- 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 app/views/notes/_reversed_notes_with_form.html.haml diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 8db88930..2db20f16 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -10,7 +10,10 @@ padding:0px; } -#notes-list li:last-child { +#new-notes-list:not(.reversed) { + border-top:1px solid #aaa; +} +#new-notes-list.reversed { border-bottom:1px solid #aaa; } @@ -48,7 +51,6 @@ .note { padding: 8px 0; - border-bottom: 1px solid #eee; overflow: hidden; display: block; img {float: left; margin-right: 10px;} @@ -70,6 +72,14 @@ .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; +} .notes-status { margin: 18px; 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..05f01847 --- /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)}"); + }); \ No newline at end of file diff --git a/app/views/projects/wall.html.haml b/app/views/projects/wall.html.haml index 1a07bc3d..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_with_form", tid: nil, tt: "wall" + = render "notes/reversed_notes_with_form", tid: nil, tt: "wall" From 07eec9c66a910b5a808852f498e1dc9c88b701d2 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 14 Sep 2012 17:01:34 +0200 Subject: [PATCH 078/123] Update Notes JS for reversed notes --- app/assets/javascripts/notes.js | 27 ++++++++++++++++++++------- app/contexts/notes/load_context.rb | 7 +++++-- app/models/note.rb | 2 +- app/views/notes/index.js.haml | 2 +- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 7cbf44b9..81bb1d6d 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -4,14 +4,17 @@ var NoteList = { 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 @@ -69,12 +72,18 @@ var NoteList = { * Replaces the content of #notes-list with the given html. */ setContent: - function(last_id, html) { + function(first_id, last_id, html) { + this.top_id = first_id; this.bottom_id = last_id; $("#notes-list").html(html); - // Init infinite scrolling + // init infinite scrolling this.initLoadMore(); + + // init getting new notes + if (this.reversed) { + this.initRefreshNew(); + } }, @@ -114,7 +123,7 @@ var NoteList = { $.ajax({ type: "GET", url: this.notes_path, - data: "loading_more=1&after_id=" + this.bottom_id + this.target_params, + 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"}); @@ -142,7 +151,9 @@ var NoteList = { this.loading_more_disabled = true; // from now on only get new notes - this.initRefreshNew(); + if (!this.reversed) { + this.initRefreshNew(); + } }, @@ -164,14 +175,14 @@ var NoteList = { }, /** - * Gets the new set of notes (i.e. all notes after ). + * Gets the new set of notes. */ getNew: function() { $.ajax({ type: "GET", url: this.notes_path, - data: "loading_new=1&after_id=" + this.bottom_id + this.target_params, + data: "loading_new=1&after_id=" + (this.reversed ? this.top_id : this.bottom_id) + this.target_params, dataType: "script"}); }, @@ -189,7 +200,9 @@ var NoteList = { */ appendNewNote: function(id, html) { - if(id != this.bottom_id) { + if (this.reversed) { + $("#new-notes-list").prepend(html); + } else { $("#new-notes-list").append(html); } } diff --git a/app/contexts/notes/load_context.rb b/app/contexts/notes/load_context.rb index c2d7644b..6d26e16a 100644 --- a/app/contexts/notes/load_context.rb +++ b/app/contexts/notes/load_context.rb @@ -4,6 +4,7 @@ module Notes target_type = params[:target_type] target_id = params[:target_id] after_id = params[:after_id] + before_id = params[:before_id] @notes = case target_type @@ -17,14 +18,16 @@ module Notes 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").limit(50) + project.common_notes.order("created_at DESC, id DESC").limit(50) when "wiki" project.wikis.reverse.map {|w| w.notes.fresh }.flatten[0..20] end @notes = if after_id @notes.where("id > ?", after_id) - else + elsif before_id + @notes.where("id < ?", before_id) + else @notes end end diff --git a/app/models/note.rb b/app/models/note.rb index 9aad8949..34edb94e 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -36,7 +36,7 @@ class Note < ActiveRecord::Base scope :today, where("created_at >= :date", date: Date.today) scope :last_week, where("created_at >= :date", date: (Date.today - 7.days)) scope :since, lambda { |day| where("created_at >= :date", date: (day)) } - scope :fresh, order("created_at ASC") + scope :fresh, order("created_at ASC, id ASC") scope :inc_author_project, includes(:project, :author) scope :inc_author, includes(:author) diff --git a/app/views/notes/index.js.haml b/app/views/notes/index.js.haml index 3d6859eb..3814dbd4 100644 --- a/app/views/notes/index.js.haml +++ b/app/views/notes/index.js.haml @@ -9,7 +9,7 @@ - else :plain - NoteList.setContent(#{@notes.last.id}, "#{escape_javascript(render 'notes/notes')}"); + NoteList.setContent(#{@notes.first.id}, #{@notes.last.id}, "#{escape_javascript(render 'notes/notes')}"); - else - if loading_more_notes? From a82977c64843aa177498f1a715121ae6e38bc323 Mon Sep 17 00:00:00 2001 From: randx Date: Sat, 15 Sep 2012 01:00:59 +0300 Subject: [PATCH 079/123] A bit of test refactoring --- Guardfile | 2 +- app/observers/users_project_observer.rb | 5 +-- spec/models/event_spec.rb | 41 +++++++++---------- spec/observers/users_project_observer_spec.rb | 41 ++++++++++--------- .../requests/gitlab_flavored_markdown_spec.rb | 1 + spec/support/gitolite_stub.rb | 34 ++------------- 6 files changed, 49 insertions(+), 75 deletions(-) diff --git a/Guardfile b/Guardfile index 0eea2ad9..50a10af9 100644 --- a/Guardfile +++ b/Guardfile @@ -1,7 +1,7 @@ # A sample Guardfile # More info at https://github.com/guard/guard#readme -guard 'rspec', :version => 2, :all_on_start => false do +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('spec/spec_helper.rb') { "spec" } diff --git a/app/observers/users_project_observer.rb b/app/observers/users_project_observer.rb index b2cea9f2..0512e606 100644 --- a/app/observers/users_project_observer.rb +++ b/app/observers/users_project_observer.rb @@ -15,10 +15,9 @@ class UsersProjectObserver < ActiveRecord::Observer def after_destroy(users_project) Event.create( - project_id: users_project.project.id, - action: Event::Left, + project_id: users_project.project.id, + action: Event::Left, author_id: users_project.user.id ) end - end diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index ee022e95..5cb68761 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -14,12 +14,12 @@ describe Event do it { should respond_to(:commits) } end - describe "Push event" do - before do + describe "Push event" do + before do project = Factory :project @user = project.owner - data = { + data = { before: "0000000000000000000000000000000000000000", after: "0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e", ref: "refs/heads/master", @@ -50,25 +50,24 @@ describe Event do it { @event.author.should == @user } end - describe "Joined project team" do - let(:project) {Factory.create :project} - let(:new_user) {Factory.create :user} - it "should create event" do - UsersProject.observers.enable :users_project_observer - expect{ - UsersProject.bulk_import(project, [new_user.id], UsersProject::DEVELOPER) - }.to change{Event.count}.by(1) + describe 'Team events' do + let(:user_project) { stub.as_null_object } + let(:observer) { UsersProjectObserver.instance } + + before { + Event.should_receive :create + } + + describe "Joined project team" do + it "should create event" do + observer.after_create user_project + end end - end - describe "Left project team" do - let(:project) {Factory.create :project} - let(:new_user) {Factory.create :user} - it "should create event" do - UsersProject.bulk_import(project, [new_user.id], UsersProject::DEVELOPER) - UsersProject.observers.enable :users_project_observer - expect{ - UsersProject.bulk_delete(project, [new_user.id]) - }.to change{Event.count}.by(1) + + describe "Left project team" do + it "should create event" do + observer.after_destroy user_project + end end end end diff --git a/spec/observers/users_project_observer_spec.rb b/spec/observers/users_project_observer_spec.rb index f38d9862..07d71da8 100644 --- a/spec/observers/users_project_observer_spec.rb +++ b/spec/observers/users_project_observer_spec.rb @@ -1,34 +1,32 @@ require 'spec_helper' describe UsersProjectObserver do - let(:user) { Factory.create :user } - let(:project) { Factory.create(:project, - code: "Fuu", - path: "Fuu" ) } - let(:users_project) { Factory.create(:users_project, - project: project, - user: user )} + let(:users_project) { stub.as_null_object } subject { UsersProjectObserver.instance } describe "#after_create" do it "should called when UsersProject created" do subject.should_receive(:after_create) + UsersProject.observers.enable :users_project_observer do - Factory.create(:users_project, - project: project, - user: user) + create(:users_project) end end + it "should send email to user" do - Notify.should_receive(:project_access_granted_email).with(users_project.id).and_return(double(deliver: true)) + Event.stub(:create => true) + Notify.should_receive(:project_access_granted_email).and_return(stub(deliver: true)) + subject.after_create(users_project) end + it "should create new event" do Event.should_receive(:create).with( - project_id: users_project.project.id, - action: Event::Joined, + project_id: users_project.project.id, + action: Event::Joined, author_id: users_project.user.id ) + subject.after_create(users_project) end end @@ -36,29 +34,32 @@ describe UsersProjectObserver do describe "#after_update" do it "should called when UsersProject updated" do subject.should_receive(:after_update) + UsersProject.observers.enable :users_project_observer do - users_project.update_attribute(:project_access, 40) + create(:users_project).update_attribute(:project_access, 40) end end + it "should send email to user" do Notify.should_receive(:project_access_granted_email).with(users_project.id).and_return(double(deliver: true)) + subject.after_update(users_project) end end + describe "#after_destroy" do it "should called when UsersProject destroyed" do subject.should_receive(:after_destroy) + UsersProject.observers.enable :users_project_observer do - UsersProject.bulk_delete( - users_project.project, - [users_project.user.id] - ) + create(:users_project).destroy end end + it "should create new event" do Event.should_receive(:create).with( - project_id: users_project.project.id, - action: Event::Left, + project_id: users_project.project.id, + action: Event::Left, author_id: users_project.user.id ) subject.after_destroy(users_project) diff --git a/spec/requests/gitlab_flavored_markdown_spec.rb b/spec/requests/gitlab_flavored_markdown_spec.rb index 1076e90c..68d354b7 100644 --- a/spec/requests/gitlab_flavored_markdown_spec.rb +++ b/spec/requests/gitlab_flavored_markdown_spec.rb @@ -25,6 +25,7 @@ describe "Gitlab Flavored Markdown" do @tag_name = "gfm-test-tag" r.git.native(:tag, {}, @tag_name, commit.id) end + after do # delete test branch and tag project.repo.git.native(:branch, {D: true}, @branch_name) diff --git a/spec/support/gitolite_stub.rb b/spec/support/gitolite_stub.rb index 037b09cd..574bb5a1 100644 --- a/spec/support/gitolite_stub.rb +++ b/spec/support/gitolite_stub.rb @@ -5,42 +5,16 @@ module GitoliteStub end def stub_gitolite_admin - gitolite_repo = mock( - clean_permissions: true, - add_permission: true - ) - - gitolite_config = mock( - add_repo: true, - get_repo: gitolite_repo, - has_repo?: true - ) - - gitolite_admin = double( - 'Gitolite::GitoliteAdmin', - config: gitolite_config, - save: true, - ) + gitolite_admin = double('Gitolite::GitoliteAdmin') + gitolite_admin.as_null_object Gitolite::GitoliteAdmin.stub(new: gitolite_admin) - end def stub_gitlab_gitolite gitolite_config = double('Gitlab::GitoliteConfig') - gitolite_config.stub( - apply: ->() { yield(self) }, - write_key: true, - rm_key: true, - update_projects: true, - update_project: true, - update_project!: true, - destroy_project: true, - destroy_project!: true, - admin_all_repo: true, - admin_all_repo!: true, - - ) + gitolite_config.stub(apply: ->() { yield(self) }) + gitolite_config.as_null_object Gitlab::GitoliteConfig.stub(new: gitolite_config) end From 9159be3a50e3bc94f30f85d9640eeac212bf0948 Mon Sep 17 00:00:00 2001 From: randx Date: Sat, 15 Sep 2012 09:49:21 +0300 Subject: [PATCH 080/123] Fix MR diff comments. Fix wiki comments loading error --- app/assets/stylesheets/sections/notes.scss | 4 ++-- app/contexts/notes/load_context.rb | 2 +- app/models/project.rb | 4 ++++ app/models/wiki.rb | 1 - app/views/merge_requests/diffs.html.haml | 4 ++++ 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 2db20f16..148807d6 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -14,7 +14,7 @@ border-top:1px solid #aaa; } #new-notes-list.reversed { - border-bottom:1px solid #aaa; + border-bottom:1px solid #ccc; } .issue_notes, @@ -227,7 +227,7 @@ td .line_note_link { } } -.note-text { +.note-text { border: 1px solid #aaa; box-shadow:none; } diff --git a/app/contexts/notes/load_context.rb b/app/contexts/notes/load_context.rb index 6d26e16a..f92a7801 100644 --- a/app/contexts/notes/load_context.rb +++ b/app/contexts/notes/load_context.rb @@ -20,7 +20,7 @@ module Notes # this is the only case, where the order is DESC project.common_notes.order("created_at DESC, id DESC").limit(50) when "wiki" - project.wikis.reverse.map {|w| w.notes.fresh }.flatten[0..20] + project.wiki_notes.limit(20) end @notes = if after_id diff --git a/app/models/project.rb b/app/models/project.rb index 4de836c7..56d5d791 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -171,6 +171,10 @@ class Project < ActiveRecord::Base end end + def wiki_notes + Note.where(noteable_id: wikis.map(&:id), noteable_type: 'Wiki', project_id: self.id) + end + def project_id self.id end diff --git a/app/models/wiki.rb b/app/models/wiki.rb index 3c4952cd..ebb1ff49 100644 --- a/app/models/wiki.rb +++ b/app/models/wiki.rb @@ -28,7 +28,6 @@ class Wiki < ActiveRecord::Base end new_wiki end - end end # == Schema Information 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(); + }); From 348def03449f8f92fc1b568df7ad2fef40343587 Mon Sep 17 00:00:00 2001 From: randx Date: Sat, 15 Sep 2012 09:58:16 +0300 Subject: [PATCH 081/123] Init mr comments when naviagate via ajax to diff --- app/views/merge_requests/diffs.js.haml | 3 +++ 1 file changed, 3 insertions(+) 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(); + }); From b8113334a86639b87d5f89cc78e2279a8ae4e38a Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Sat, 15 Sep 2012 11:54:46 +0200 Subject: [PATCH 082/123] Highlight voting notes for issues and merge requests --- app/assets/stylesheets/sections/notes.scss | 13 +++++++++++++ app/helpers/notes_helper.rb | 8 ++++++++ app/views/issues/show.html.haml | 2 +- app/views/merge_requests/_show.html.haml | 2 +- app/views/notes/_note.html.haml | 2 +- 5 files changed, 24 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 148807d6..06b929c6 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -81,6 +81,19 @@ border-top: 1px solid #eee; } +/* mark vote notes */ +.voting_notes .note { + padding: 8px 0 8px 12px; + &.upvote { + padding-left: 8px; + border-left: 4px solid #468847; + } + &.downvote { + padding-left: 8px; + border-left: 4px solid #B94A48; + } +} + .notes-status { margin: 18px; } diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index 28701661..65389e38 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -6,4 +6,12 @@ module NotesHelper def loading_new_notes? params[:loading_new].present? end + + def note_vote_class(note) + if note.upvote? + "vote upvote" + elsif note.downvote? + "vote downvote" + end + end end diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index 0b72a820..e7365e10 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -61,4 +61,4 @@ = markdown @issue.description -.issue_notes#notes= render "notes/notes_with_form", 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/merge_requests/_show.html.haml b/app/views/merge_requests/_show.html.haml index 40b72190..f1d0c8aa 100644 --- a/app/views/merge_requests/_show.html.haml +++ b/app/views/merge_requests/_show.html.haml @@ -15,7 +15,7 @@ %i.icon-list-alt Diff -.merge_request_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" } +.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 diff --git a/app/views/notes/_note.html.haml b/app/views/notes/_note.html.haml index 3412e4eb..23145f12 100644 --- a/app/views/notes/_note.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 From 6aebb76b5d05bf7668a8f389a00648fdb405af7d Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Sat, 15 Sep 2012 11:55:17 +0200 Subject: [PATCH 083/123] Update votes when creating or refreshing notes --- app/assets/javascripts/notes.js | 43 ++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 81bb1d6d..7b59cc77 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -21,15 +21,18 @@ var NoteList = { this.getContent(); $("#notes-list, #new-notes-list").on("ajax:success", ".delete-note", function() { - $(this).closest('li').fadeOut(); + $(this).closest('li').fadeOut(function() { + $(this).remove(); + NoteList.updateVotes(); + }); }); $(".note-form-holder").on("ajax:before", function(){ - $(".submit_note").disable() + $(".submit_note").disable(); }) $(".note-form-holder").on("ajax:complete", function(){ - $(".submit_note").enable() + $(".submit_note").enable(); }) disableButtonIfEmptyField(".note-text", ".submit_note"); @@ -154,6 +157,8 @@ var NoteList = { if (!this.reversed) { this.initRefreshNew(); } + // make sure we are up to date + this.updateVotes(); }, @@ -193,6 +198,7 @@ var NoteList = { replaceNewNotes: function(html) { $("#new-notes-list").html(html); + this.updateVotes(); }, /** @@ -205,6 +211,37 @@ var NoteList = { } 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)); + } } }; From 74cfab692fd9808c1ea6a6cc6f45c348deb4fd72 Mon Sep 17 00:00:00 2001 From: Tobias Pfeiffer Date: Sat, 15 Sep 2012 20:26:08 +0200 Subject: [PATCH 084/123] Renamed unicorn.rb.orig to unicorn.rb.example since this seems to be more in line with the common used naming in the config directory. Plus seeing *.orig files I think of the leftovers of git merges, which left me puzzled for quite some time. --- config/{unicorn.rb.orig => unicorn.rb.example} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename config/{unicorn.rb.orig => unicorn.rb.example} (100%) 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 From fa529c789c6d5e6c7c52de73166007e4650a46fa Mon Sep 17 00:00:00 2001 From: Tobias Pfeiffer Date: Sat, 15 Sep 2012 21:23:41 +0200 Subject: [PATCH 085/123] added the name change to the installation.md - thanks and nice catch to @NARKOZ --- doc/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/installation.md b/doc/installation.md index af169d81..d5d1ccdd 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -252,7 +252,7 @@ You can login via web using admin generated with setup: ## 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 ## 2. Nginx From 296e322bfc896f99b15d0639b25745a22a73e9ce Mon Sep 17 00:00:00 2001 From: Tobias Pfeiffer Date: Sat, 15 Sep 2012 21:52:01 +0200 Subject: [PATCH 086/123] the rake was missing in fron of the gitlab:test task --- doc/development.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/development.md b/doc/development.md index 55be2bc3..741f5a9f 100644 --- a/doc/development.md +++ b/doc/development.md @@ -36,7 +36,7 @@ ### 3. Run Tests # All in one - bundle exec gitlab:test + bundle exec rake gitlab:test # Rspec bundle exec rake spec From 9c117f263646635f03b50cac38db4fb830500642 Mon Sep 17 00:00:00 2001 From: Tobias Pfeiffer Date: Sat, 15 Sep 2012 21:53:45 +0200 Subject: [PATCH 087/123] The project doesn't use cucumber(anymore?), it uses spinach --- doc/development.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/development.md b/doc/development.md index 741f5a9f..67bcb8e1 100644 --- a/doc/development.md +++ b/doc/development.md @@ -41,5 +41,5 @@ # Rspec bundle exec rake spec - # Cucumber - bundle exec rake cucumber + # Spinach + bundle exec rake spinach From caef9ed1121a16ca0cc78715695daaa974271bfd Mon Sep 17 00:00:00 2001 From: randx Date: Sun, 16 Sep 2012 13:39:49 +0300 Subject: [PATCH 088/123] Update installation doc with branch names --- doc/installation.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/installation.md b/doc/installation.md index d5d1ccdd..345d801d 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -152,7 +152,14 @@ and ensure you have followed all of the above steps carefully. sudo pip install pygments sudo gem install bundler cd /home/gitlab + + # 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 From 4f4c401f77522c27df7afdc25eeef39de76e241b Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 16 Sep 2012 04:05:13 -0400 Subject: [PATCH 089/123] Don't instantiate Resque::Server in routes It still works, and it cleans up the output of `rake routes`. --- config/routes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 84a0c6ab..858111f2 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', as: 'resque' + mount Resque::Server => '/info/resque', as: 'resque' # Enable Grack support mount Grack::Bundle.new({ From 94f91146f15c955b02e9f3717b9bf7506019f63d Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 16 Sep 2012 04:51:26 -0400 Subject: [PATCH 090/123] Limit admin/logs and admin/resque routes to the actions that are used --- config/routes.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index 858111f2..77cde722 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -53,8 +53,8 @@ Gitlab::Application.routes.draw do resources :hooks, :only => [:index, :create, :destroy] do get :test end - resource :logs - resource :resque, :controller => 'resque' + resource :logs, only: [:show] + resource :resque, :controller => 'resque', only: [:show] root :to => "dashboard#index" end From d7eb7970249b662ebcc2673001503a247d7fbe48 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 16 Sep 2012 07:22:46 -0400 Subject: [PATCH 091/123] 1.9 Hash syntax in routes.rb Also cleans up some alignment and removes unnecessary "to: " arguments --- config/routes.rb | 103 ++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 51 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index 77cde722..c226a473 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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,19 +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] - 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, only: [:show] - resource :resque, :controller => 'resque', only: [:show] - root :to => "dashboard#index" + resource :resque, controller: 'resque', only: [:show] + root to: "dashboard#index" end get "errors/githost" @@ -63,31 +63,32 @@ Gitlab::Application.routes.draw do # # Profile Area # - get "profile/account", :to => "profile#account" - get "profile/history", :to => "profile#history" - 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" @@ -95,7 +96,7 @@ Gitlab::Application.routes.draw do get "files" end - resources :wikis, :only => [:show, :edit, :destroy, :create] do + resources :wikis, only: [:show, :edit, :destroy, :create] do collection do get :pages end @@ -114,46 +115,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 @@ -178,7 +178,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 @@ -194,7 +194,7 @@ Gitlab::Application.routes.draw do end resources :team_members resources :milestones - resources :labels, :only => [:index] + resources :labels, only: [:index] resources :issues do collection do @@ -203,11 +203,12 @@ Gitlab::Application.routes.draw do 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 From 89069dc5f7714472b106914a27c462755ab01396 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 16 Sep 2012 07:31:51 -0400 Subject: [PATCH 092/123] Remove unused ProfileController#password action --- app/controllers/profile_controller.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/controllers/profile_controller.rb b/app/controllers/profile_controller.rb index ba68af2e..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"} From 83f24de3520ba1c49544b268253a0665831c2bd5 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 16 Sep 2012 04:21:46 -0400 Subject: [PATCH 093/123] Add routing specs --- spec/routing/admin_routing_spec.rb | 166 ++++++++ spec/routing/routing_spec.rb | 588 +++++++++++++++++++++++++++++ 2 files changed, 754 insertions(+) create mode 100644 spec/routing/admin_routing_spec.rb create mode 100644 spec/routing/routing_spec.rb diff --git a/spec/routing/admin_routing_spec.rb b/spec/routing/admin_routing_spec.rb new file mode 100644 index 00000000..60261c7a --- /dev/null +++ b/spec/routing/admin_routing_spec.rb @@ -0,0 +1,166 @@ +require 'spec_helper' + +# team_update_admin_user PUT /admin/users/:id/team_update(.:format) admin/users#team_update +# block_admin_user PUT /admin/users/:id/block(.:format) admin/users#block +# unblock_admin_user PUT /admin/users/:id/unblock(.:format) admin/users#unblock +# admin_users GET /admin/users(.:format) admin/users#index +# POST /admin/users(.:format) admin/users#create +# new_admin_user GET /admin/users/new(.:format) admin/users#new +# edit_admin_user GET /admin/users/:id/edit(.:format) admin/users#edit +# admin_user GET /admin/users/:id(.:format) admin/users#show +# PUT /admin/users/:id(.:format) admin/users#update +# DELETE /admin/users/:id(.:format) admin/users#destroy +describe Admin::UsersController, "routing" do + it "to #team_update" do + put("/admin/users/1/team_update").should route_to('admin/users#team_update', id: '1') + end + + it "to #block" do + put("/admin/users/1/block").should route_to('admin/users#block', id: '1') + end + + it "to #unblock" do + put("/admin/users/1/unblock").should route_to('admin/users#unblock', id: '1') + end + + it "to #index" do + get("/admin/users").should route_to('admin/users#index') + end + + it "to #show" do + get("/admin/users/1").should route_to('admin/users#show', id: '1') + end + + it "to #create" do + post("/admin/users").should route_to('admin/users#create') + end + + it "to #new" do + get("/admin/users/new").should route_to('admin/users#new') + end + + it "to #edit" do + get("/admin/users/1/edit").should route_to('admin/users#edit', id: '1') + end + + it "to #show" do + get("/admin/users/1").should route_to('admin/users#show', id: '1') + end + + it "to #update" do + put("/admin/users/1").should route_to('admin/users#update', id: '1') + end + + it "to #destroy" do + delete("/admin/users/1").should route_to('admin/users#destroy', id: '1') + end +end + +# team_admin_project GET /admin/projects/:id/team(.:format) admin/projects#team {:id=>/[^\/]+/} +# team_update_admin_project PUT /admin/projects/:id/team_update(.:format) admin/projects#team_update {:id=>/[^\/]+/} +# admin_projects GET /admin/projects(.:format) admin/projects#index {:id=>/[^\/]+/} +# POST /admin/projects(.:format) admin/projects#create {:id=>/[^\/]+/} +# new_admin_project GET /admin/projects/new(.:format) admin/projects#new {:id=>/[^\/]+/} +# edit_admin_project GET /admin/projects/:id/edit(.:format) admin/projects#edit {:id=>/[^\/]+/} +# admin_project GET /admin/projects/:id(.:format) admin/projects#show {:id=>/[^\/]+/} +# PUT /admin/projects/:id(.:format) admin/projects#update {:id=>/[^\/]+/} +# DELETE /admin/projects/:id(.:format) admin/projects#destroy {:id=>/[^\/]+/} +describe Admin::ProjectsController, "routing" do + it "to #team" do + get("/admin/projects/gitlab/team").should route_to('admin/projects#team', id: 'gitlab') + end + + it "to #team_update" do + put("/admin/projects/gitlab/team_update").should route_to('admin/projects#team_update', id: 'gitlab') + end + + it "to #index" do + get("/admin/projects").should route_to('admin/projects#index') + end + + it "to #create" do + post("/admin/projects").should route_to('admin/projects#create') + end + + it "to #new" do + get("/admin/projects/new").should route_to('admin/projects#new') + end + + it "to #edit" do + get("/admin/projects/gitlab/edit").should route_to('admin/projects#edit', id: 'gitlab') + end + + it "to #show" do + get("/admin/projects/gitlab").should route_to('admin/projects#show', id: 'gitlab') + end + + it "to #update" do + put("/admin/projects/gitlab").should route_to('admin/projects#update', id: 'gitlab') + end + + it "to #destroy" do + delete("/admin/projects/gitlab").should route_to('admin/projects#destroy', id: 'gitlab') + end +end + +# edit_admin_team_member GET /admin/team_members/:id/edit(.:format) admin/team_members#edit +# admin_team_member PUT /admin/team_members/:id(.:format) admin/team_members#update +# DELETE /admin/team_members/:id(.:format) admin/team_members#destroy +describe Admin::TeamMembersController, "routing" do + it "to #edit" do + get("/admin/team_members/1/edit").should route_to('admin/team_members#edit', id: '1') + end + + it "to #update" do + put("/admin/team_members/1").should route_to('admin/team_members#update', id: '1') + end + + it "to #destroy" do + delete("/admin/team_members/1").should route_to('admin/team_members#destroy', id: '1') + end +end + +# admin_hook_test GET /admin/hooks/:hook_id/test(.:format) admin/hooks#test +# admin_hooks GET /admin/hooks(.:format) admin/hooks#index +# POST /admin/hooks(.:format) admin/hooks#create +# admin_hook DELETE /admin/hooks/:id(.:format) admin/hooks#destroy +describe Admin::HooksController, "routing" do + it "to #test" do + get("/admin/hooks/1/test").should route_to('admin/hooks#test', hook_id: '1') + end + + it "to #index" do + get("/admin/hooks").should route_to('admin/hooks#index') + end + + it "to #create" do + post("/admin/hooks").should route_to('admin/hooks#create') + end + + it "to #destroy" do + delete("/admin/hooks/1").should route_to('admin/hooks#destroy', id: '1') + end + +end + +# admin_logs GET /admin/logs(.:format) admin/logs#show +describe Admin::LogsController, "routing" do + it "to #show" do + get("/admin/logs").should route_to('admin/logs#show') + end +end + +# admin_resque GET /admin/resque(.:format) admin/resque#show +describe Admin::ResqueController, "routing" do + it "to #show" do + get("/admin/resque").should route_to('admin/resque#show') + end +end + +# admin_root /admin(.:format) admin/dashboard#index +describe Admin::DashboardController, "routing" do + it "to #index" do + get("/admin").should route_to('admin/dashboard#index') + end +end + diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb new file mode 100644 index 00000000..f69422ba --- /dev/null +++ b/spec/routing/routing_spec.rb @@ -0,0 +1,588 @@ +require 'spec_helper' + +# Shared examples for a resource inside a Project +# +# By default it tests all the default REST actions: index, create, new, edit, +# show, update, and destroy. You can remove actions by customizing the +# `actions` variable. +# +# It also expects a `controller` variable to be available which defines both +# the path to the resource as well as the controller name. +# +# Examples +# +# # Default behavior +# it_behaves_like "RESTful project resources" do +# let(:controller) { 'issues' } +# end +# +# # Customizing actions +# it_behaves_like "RESTful project resources" do +# let(:actions) { [:index] } +# let(:controller) { 'issues' } +# end +shared_examples "RESTful project resources" do + let(:actions) { [:index, :create, :new, :edit, :show, :update, :destroy] } + + it "to #index" do + get("/gitlabhq/#{controller}").should route_to("#{controller}#index", project_id: 'gitlabhq') if actions.include?(:index) + end + + it "to #create" do + post("/gitlabhq/#{controller}").should route_to("#{controller}#create", project_id: 'gitlabhq') if actions.include?(:create) + end + + it "to #new" do + get("/gitlabhq/#{controller}/new").should route_to("#{controller}#new", project_id: 'gitlabhq') if actions.include?(:new) + end + + it "to #edit" do + get("/gitlabhq/#{controller}/1/edit").should route_to("#{controller}#edit", project_id: 'gitlabhq', id: '1') if actions.include?(:edit) + end + + it "to #show" do + get("/gitlabhq/#{controller}/1").should route_to("#{controller}#show", project_id: 'gitlabhq', id: '1') if actions.include?(:show) + end + + it "to #update" do + put("/gitlabhq/#{controller}/1").should route_to("#{controller}#update", project_id: 'gitlabhq', id: '1') if actions.include?(:update) + end + + it "to #destroy" do + delete("/gitlabhq/#{controller}/1").should route_to("#{controller}#destroy", project_id: 'gitlabhq', id: '1') if actions.include?(:destroy) + end +end + +# search GET /search(.:format) search#show +describe SearchController, "routing" do + it "to #show" do + get("/search").should route_to('search#show') + end +end + +# gitlab_api /api Gitlab::API +# resque /info/resque Resque::Server +# /:path Grack +describe "Mounted Apps", "routing" do + it "to API" do + get("/api").should be_routable + end + + it "to Resque" do + pending + get("/info/resque").should be_routable + end + + it "to Grack" do + get("/gitlabhq.git").should be_routable + end +end + +# help GET /help(.:format) help#index +# help_permissions GET /help/permissions(.:format) help#permissions +# help_workflow GET /help/workflow(.:format) help#workflow +# help_api GET /help/api(.:format) help#api +# help_web_hooks GET /help/web_hooks(.:format) help#web_hooks +# help_system_hooks GET /help/system_hooks(.:format) help#system_hooks +# help_markdown GET /help/markdown(.:format) help#markdown +# help_ssh GET /help/ssh(.:format) help#ssh +describe HelpController, "routing" do + it "to #index" do + get("/help").should route_to('help#index') + end + + it "to #permissions" do + get("/help/permissions").should route_to('help#permissions') + end + + it "to #workflow" do + get("/help/workflow").should route_to('help#workflow') + end + + it "to #api" do + get("/help/api").should route_to('help#api') + end + + it "to #web_hooks" do + get("/help/web_hooks").should route_to('help#web_hooks') + end + + it "to #system_hooks" do + get("/help/system_hooks").should route_to('help#system_hooks') + end + + it "to #markdown" do + get("/help/markdown").should route_to('help#markdown') + end + + it "to #ssh" do + get("/help/ssh").should route_to('help#ssh') + end +end + +# errors_githost GET /errors/githost(.:format) errors#githost +describe ErrorsController, "routing" do + it "to #githost" do + get("/errors/githost").should route_to('errors#githost') + end +end + +# profile_account GET /profile/account(.:format) profile#account +# profile_history GET /profile/history(.:format) profile#history +# profile_password PUT /profile/password(.:format) profile#password_update +# profile_token GET /profile/token(.:format) profile#token +# profile_reset_private_token PUT /profile/reset_private_token(.:format) profile#reset_private_token +# profile GET /profile(.:format) profile#show +# profile_design GET /profile/design(.:format) profile#design +# profile_update PUT /profile/update(.:format) profile#update +describe ProfileController, "routing" do + it "to #account" do + get("/profile/account").should route_to('profile#account') + end + + it "to #history" do + get("/profile/history").should route_to('profile#history') + end + + it "to #password_update" do + put("/profile/password").should route_to('profile#password_update') + end + + it "to #token" do + get("/profile/token").should route_to('profile#token') + end + + it "to #reset_private_token" do + put("/profile/reset_private_token").should route_to('profile#reset_private_token') + end + + it "to #show" do + get("/profile").should route_to('profile#show') + end + + it "to #design" do + get("/profile/design").should route_to('profile#design') + end + + it "to #update" do + put("/profile/update").should route_to('profile#update') + end +end + +# keys GET /keys(.:format) keys#index +# POST /keys(.:format) keys#create +# new_key GET /keys/new(.:format) keys#new +# edit_key GET /keys/:id/edit(.:format) keys#edit +# key GET /keys/:id(.:format) keys#show +# PUT /keys/:id(.:format) keys#update +# DELETE /keys/:id(.:format) keys#destroy +describe KeysController, "routing" do + it "to #index" do + get("/keys").should route_to('keys#index') + end + + it "to #create" do + post("/keys").should route_to('keys#create') + end + + it "to #new" do + get("/keys/new").should route_to('keys#new') + end + + it "to #edit" do + get("/keys/1/edit").should route_to('keys#edit', id: '1') + end + + it "to #show" do + get("/keys/1").should route_to('keys#show', id: '1') + end + + it "to #update" do + put("/keys/1").should route_to('keys#update', id: '1') + end + + it "to #destroy" do + delete("/keys/1").should route_to('keys#destroy', id: '1') + end +end + +# dashboard GET /dashboard(.:format) dashboard#index +# dashboard_issues GET /dashboard/issues(.:format) dashboard#issues +# dashboard_merge_requests GET /dashboard/merge_requests(.:format) dashboard#merge_requests +# root / dashboard#index +describe DashboardController, "routing" do + it "to #index" do + get("/dashboard").should route_to('dashboard#index') + get("/").should route_to('dashboard#index') + end + + it "to #issues" do + get("/dashboard/issues").should route_to('dashboard#issues') + end + + it "to #merge_requests" do + get("/dashboard/merge_requests").should route_to('dashboard#merge_requests') + end +end + +# projects POST /projects(.:format) projects#create +# new_project GET /projects/new(.:format) projects#new +# team_project GET /:id/team(.:format) projects#team +# wall_project GET /:id/wall(.:format) projects#wall +# graph_project GET /:id/graph(.:format) projects#graph +# files_project GET /:id/files(.:format) projects#files +# edit_project GET /:id/edit(.:format) projects#edit +# project GET /:id(.:format) projects#show +# PUT /:id(.:format) projects#update +# DELETE /:id(.:format) projects#destroy +describe ProjectsController, "routing" do + it "to #create" do + post("/projects").should route_to('projects#create') + end + + it "to #new" do + get("/projects/new").should route_to('projects#new') + end + + it "to #team" do + get("/gitlabhq/team").should route_to('projects#team', id: 'gitlabhq') + end + + it "to #wall" do + get("/gitlabhq/wall").should route_to('projects#wall', id: 'gitlabhq') + end + + it "to #graph" do + get("/gitlabhq/graph").should route_to('projects#graph', id: 'gitlabhq') + end + + it "to #files" do + get("/gitlabhq/files").should route_to('projects#files', id: 'gitlabhq') + end + + it "to #edit" do + get("/gitlabhq/edit").should route_to('projects#edit', id: 'gitlabhq') + end + + it "to #show" do + get("/gitlabhq").should route_to('projects#show', id: 'gitlabhq') + end + + it "to #update" do + put("/gitlabhq").should route_to('projects#update', id: 'gitlabhq') + end + + it "to #destroy" do + delete("/gitlabhq").should route_to('projects#destroy', id: 'gitlabhq') + end +end + +# new_user_session GET /users/sign_in(.:format) devise/sessions#new +# user_session POST /users/sign_in(.:format) devise/sessions#create +# destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy +# user_omniauth_authorize /users/auth/:provider(.:format) omniauth_callbacks#passthru +# user_omniauth_callback /users/auth/:action/callback(.:format) omniauth_callbacks#(?-mix:(?!)) +# user_password POST /users/password(.:format) devise/passwords#create +# new_user_password GET /users/password/new(.:format) devise/passwords#new +# edit_user_password GET /users/password/edit(.:format) devise/passwords#edit +# PUT /users/password(.:format) devise/passwords#update +describe "Authentication", "routing" do + # pending +end + +# pages_project_wikis GET /:project_id/wikis/pages(.:format) wikis#pages +# history_project_wiki GET /:project_id/wikis/:id/history(.:format) wikis#history +# project_wikis POST /:project_id/wikis(.:format) wikis#create +# edit_project_wiki GET /:project_id/wikis/:id/edit(.:format) wikis#edit +# project_wiki GET /:project_id/wikis/:id(.:format) wikis#show +# DELETE /:project_id/wikis/:id(.:format) wikis#destroy +describe WikisController, "routing" do + it "to #pages" do + get("/gitlabhq/wikis/pages").should route_to('wikis#pages', project_id: 'gitlabhq') + end + + it "to #history" do + get("/gitlabhq/wikis/1/history").should route_to('wikis#history', project_id: 'gitlabhq', id: '1') + end + + it_behaves_like "RESTful project resources" do + let(:actions) { [:create, :edit, :show, :destroy] } + let(:controller) { 'wikis' } + end +end + +# branches_project_repository GET /:project_id/repository/branches(.:format) repositories#branches +# tags_project_repository GET /:project_id/repository/tags(.:format) repositories#tags +# archive_project_repository GET /:project_id/repository/archive(.:format) repositories#archive +# project_repository POST /:project_id/repository(.:format) repositories#create +# new_project_repository GET /:project_id/repository/new(.:format) repositories#new +# edit_project_repository GET /:project_id/repository/edit(.:format) repositories#edit +# GET /:project_id/repository(.:format) repositories#show +# PUT /:project_id/repository(.:format) repositories#update +# DELETE /:project_id/repository(.:format) repositories#destroy +describe RepositoriesController, "routing" do + it "to #branches" do + get("/gitlabhq/repository/branches").should route_to('repositories#branches', project_id: 'gitlabhq') + end + + it "to #tags" do + get("/gitlabhq/repository/tags").should route_to('repositories#tags', project_id: 'gitlabhq') + end + + it "to #archive" do + get("/gitlabhq/repository/archive").should route_to('repositories#archive', project_id: 'gitlabhq') + end + + it "to #create" do + post("/gitlabhq/repository").should route_to('repositories#create', project_id: 'gitlabhq') + end + + it "to #new" do + get("/gitlabhq/repository/new").should route_to('repositories#new', project_id: 'gitlabhq') + end + + it "to #edit" do + get("/gitlabhq/repository/edit").should route_to('repositories#edit', project_id: 'gitlabhq') + end + + it "to #show" do + get("/gitlabhq/repository").should route_to('repositories#show', project_id: 'gitlabhq') + end + + it "to #update" do + put("/gitlabhq/repository").should route_to('repositories#update', project_id: 'gitlabhq') + end + + it "to #destroy" do + delete("/gitlabhq/repository").should route_to('repositories#destroy', project_id: 'gitlabhq') + end +end + +# project_deploy_keys GET /:project_id/deploy_keys(.:format) deploy_keys#index +# POST /:project_id/deploy_keys(.:format) deploy_keys#create +# new_project_deploy_key GET /:project_id/deploy_keys/new(.:format) deploy_keys#new +# edit_project_deploy_key GET /:project_id/deploy_keys/:id/edit(.:format) deploy_keys#edit +# project_deploy_key GET /:project_id/deploy_keys/:id(.:format) deploy_keys#show +# PUT /:project_id/deploy_keys/:id(.:format) deploy_keys#update +# DELETE /:project_id/deploy_keys/:id(.:format) deploy_keys#destroy +describe DeployKeysController, "routing" do + it_behaves_like "RESTful project resources" do + let(:controller) { 'deploy_keys' } + end +end + +# project_protected_branches GET /:project_id/protected_branches(.:format) protected_branches#index +# POST /:project_id/protected_branches(.:format) protected_branches#create +# project_protected_branch DELETE /:project_id/protected_branches/:id(.:format) protected_branches#destroy +describe ProtectedBranchesController, "routing" do + it_behaves_like "RESTful project resources" do + let(:actions) { [:index, :create, :destroy] } + let(:controller) { 'protected_branches' } + end +end + +# switch_project_refs GET /:project_id/switch(.:format) refs#switch +# tree_project_ref GET /:project_id/:id/tree(.:format) refs#tree +# logs_tree_project_ref GET /:project_id/:id/logs_tree(.:format) refs#logs_tree +# blob_project_ref GET /:project_id/:id/blob(.:format) refs#blob +# tree_file_project_ref GET /:project_id/:id/tree/:path(.:format) refs#tree +# logs_file_project_ref GET /:project_id/:id/logs_tree/:path(.:format) refs#logs_tree +# blame_file_project_ref GET /:project_id/:id/blame/:path(.:format) refs#blame +describe RefsController, "routing" do + it "to #switch" do + get("/gitlabhq/switch").should route_to('refs#switch', project_id: 'gitlabhq') + end + + it "to #tree" do + get("/gitlabhq/stable/tree").should route_to('refs#tree', project_id: 'gitlabhq', id: 'stable') + get("/gitlabhq/stable/tree/foo/bar/baz").should route_to('refs#tree', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz') + end + + it "to #logs_tree" do + get("/gitlabhq/stable/logs_tree").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable') + get("/gitlabhq/stable/logs_tree/foo/bar/baz").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz') + end + + it "to #blob" do + get("/gitlabhq/stable/blob").should route_to('refs#blob', project_id: 'gitlabhq', id: 'stable') + end + + it "to #blame" do + get("/gitlabhq/stable/blame/foo/bar/baz").should route_to('refs#blame', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz') + end +end + +# diffs_project_merge_request GET /:project_id/merge_requests/:id/diffs(.:format) merge_requests#diffs +# automerge_project_merge_request GET /:project_id/merge_requests/:id/automerge(.:format) merge_requests#automerge +# automerge_check_project_merge_request GET /:project_id/merge_requests/:id/automerge_check(.:format) merge_requests#automerge_check +# raw_project_merge_request GET /:project_id/merge_requests/:id/raw(.:format) merge_requests#raw +# branch_from_project_merge_requests GET /:project_id/merge_requests/branch_from(.:format) merge_requests#branch_from +# branch_to_project_merge_requests GET /:project_id/merge_requests/branch_to(.:format) merge_requests#branch_to +# project_merge_requests GET /:project_id/merge_requests(.:format) merge_requests#index +# POST /:project_id/merge_requests(.:format) merge_requests#create +# new_project_merge_request GET /:project_id/merge_requests/new(.:format) merge_requests#new +# edit_project_merge_request GET /:project_id/merge_requests/:id/edit(.:format) merge_requests#edit +# project_merge_request GET /:project_id/merge_requests/:id(.:format) merge_requests#show +# PUT /:project_id/merge_requests/:id(.:format) merge_requests#update +# DELETE /:project_id/merge_requests/:id(.:format) merge_requests#destroy +describe MergeRequestsController, "routing" do + it "to #diffs" do + get("/gitlabhq/merge_requests/1/diffs").should route_to('merge_requests#diffs', project_id: 'gitlabhq', id: '1') + end + + it "to #automerge" do + get("/gitlabhq/merge_requests/1/automerge").should route_to('merge_requests#automerge', project_id: 'gitlabhq', id: '1') + end + + it "to #automerge_check" do + get("/gitlabhq/merge_requests/1/automerge_check").should route_to('merge_requests#automerge_check', project_id: 'gitlabhq', id: '1') + end + + it "to #raw" do + get("/gitlabhq/merge_requests/1/raw").should route_to('merge_requests#raw', project_id: 'gitlabhq', id: '1') + end + + it "to #branch_from" do + get("/gitlabhq/merge_requests/branch_from").should route_to('merge_requests#branch_from', project_id: 'gitlabhq') + end + + it "to #branch_to" do + get("/gitlabhq/merge_requests/branch_to").should route_to('merge_requests#branch_to', project_id: 'gitlabhq') + end + + it_behaves_like "RESTful project resources" do + let(:controller) { 'merge_requests' } + end +end + +# raw_project_snippet GET /:project_id/snippets/:id/raw(.:format) snippets#raw +# project_snippets GET /:project_id/snippets(.:format) snippets#index +# POST /:project_id/snippets(.:format) snippets#create +# new_project_snippet GET /:project_id/snippets/new(.:format) snippets#new +# edit_project_snippet GET /:project_id/snippets/:id/edit(.:format) snippets#edit +# project_snippet GET /:project_id/snippets/:id(.:format) snippets#show +# PUT /:project_id/snippets/:id(.:format) snippets#update +# DELETE /:project_id/snippets/:id(.:format) snippets#destroy +describe SnippetsController, "routing" do + it "to #raw" do + get("/gitlabhq/snippets/1/raw").should route_to('snippets#raw', project_id: 'gitlabhq', id: '1') + end + + it_behaves_like "RESTful project resources" do + let(:controller) { 'snippets' } + end +end + +# test_project_hook GET /:project_id/hooks/:id/test(.:format) hooks#test +# project_hooks GET /:project_id/hooks(.:format) hooks#index +# POST /:project_id/hooks(.:format) hooks#create +# project_hook DELETE /:project_id/hooks/:id(.:format) hooks#destroy +describe HooksController, "routing" do + it "to #test" do + get("/gitlabhq/hooks/1/test").should route_to('hooks#test', project_id: 'gitlabhq', id: '1') + end + + it_behaves_like "RESTful project resources" do + let(:actions) { [:index, :create, :destroy] } + let(:controller) { 'hooks' } + end +end + +# compare_project_commits GET /:project_id/commits/compare(.:format) commits#compare +# patch_project_commit GET /:project_id/commits/:id/patch(.:format) commits#patch +# project_commits GET /:project_id/commits(.:format) commits#index +# POST /:project_id/commits(.:format) commits#create +# new_project_commit GET /:project_id/commits/new(.:format) commits#new +# edit_project_commit GET /:project_id/commits/:id/edit(.:format) commits#edit +# project_commit GET /:project_id/commits/:id(.:format) commits#show +# PUT /:project_id/commits/:id(.:format) commits#update +# DELETE /:project_id/commits/:id(.:format) commits#destroy +describe CommitsController, "routing" do + it "to #compare" do + get("/gitlabhq/commits/compare").should route_to('commits#compare', project_id: 'gitlabhq') + end + + it "to #patch" do + get("/gitlabhq/commits/1/patch").should route_to('commits#patch', project_id: 'gitlabhq', id: '1') + end + + it_behaves_like "RESTful project resources" do + let(:controller) { 'commits' } + end +end + +# project_team_members GET /:project_id/team_members(.:format) team_members#index +# POST /:project_id/team_members(.:format) team_members#create +# new_project_team_member GET /:project_id/team_members/new(.:format) team_members#new +# edit_project_team_member GET /:project_id/team_members/:id/edit(.:format) team_members#edit +# project_team_member GET /:project_id/team_members/:id(.:format) team_members#show +# PUT /:project_id/team_members/:id(.:format) team_members#update +# DELETE /:project_id/team_members/:id(.:format) team_members#destroy +describe TeamMembersController, "routing" do + it_behaves_like "RESTful project resources" do + let(:controller) { 'team_members' } + end +end + +# project_milestones GET /:project_id/milestones(.:format) milestones#index +# POST /:project_id/milestones(.:format) milestones#create +# new_project_milestone GET /:project_id/milestones/new(.:format) milestones#new +# edit_project_milestone GET /:project_id/milestones/:id/edit(.:format) milestones#edit +# project_milestone GET /:project_id/milestones/:id(.:format) milestones#show +# PUT /:project_id/milestones/:id(.:format) milestones#update +# DELETE /:project_id/milestones/:id(.:format) milestones#destroy +describe MilestonesController, "routing" do + it_behaves_like "RESTful project resources" do + let(:controller) { 'milestones' } + end +end + +# project_labels GET /:project_id/labels(.:format) labels#index +describe LabelsController, "routing" do + it "to #index" do + get("/gitlabhq/labels").should route_to('labels#index', project_id: 'gitlabhq') + end +end + +# sort_project_issues POST /:project_id/issues/sort(.:format) issues#sort +# bulk_update_project_issues POST /:project_id/issues/bulk_update(.:format) issues#bulk_update +# search_project_issues GET /:project_id/issues/search(.:format) issues#search +# project_issues GET /:project_id/issues(.:format) issues#index +# POST /:project_id/issues(.:format) issues#create +# new_project_issue GET /:project_id/issues/new(.:format) issues#new +# edit_project_issue GET /:project_id/issues/:id/edit(.:format) issues#edit +# project_issue GET /:project_id/issues/:id(.:format) issues#show +# PUT /:project_id/issues/:id(.:format) issues#update +# DELETE /:project_id/issues/:id(.:format) issues#destroy +describe IssuesController, "routing" do + it "to #sort" do + post("/gitlabhq/issues/sort").should route_to('issues#sort', project_id: 'gitlabhq') + end + + it "to #bulk_update" do + post("/gitlabhq/issues/bulk_update").should route_to('issues#bulk_update', project_id: 'gitlabhq') + end + + it "to #search" do + get("/gitlabhq/issues/search").should route_to('issues#search', project_id: 'gitlabhq') + end + + it_behaves_like "RESTful project resources" do + let(:controller) { 'issues' } + end +end + +# preview_project_notes POST /:project_id/notes/preview(.:format) notes#preview +# project_notes GET /:project_id/notes(.:format) notes#index +# POST /:project_id/notes(.:format) notes#create +# project_note DELETE /:project_id/notes/:id(.:format) notes#destroy +describe NotesController, "routing" do + it "to #preview" do + post("/gitlabhq/notes/preview").should route_to('notes#preview', project_id: 'gitlabhq') + end + + it_behaves_like "RESTful project resources" do + let(:actions) { [:index, :create, :destroy] } + let(:controller) { 'notes' } + end +end From 925183ed7a8eb392e008764483f59c319e22a59c Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 16 Sep 2012 07:44:54 -0400 Subject: [PATCH 094/123] Add an AdminController base class for Admin controllers Handles stuff that's shared across admin controllers. --- app/controllers/admin/dashboard_controller.rb | 6 +----- app/controllers/admin/hooks_controller.rb | 8 ++------ app/controllers/admin/logs_controller.rb | 6 +----- app/controllers/admin/projects_controller.rb | 9 +++------ app/controllers/admin/resque_controller.rb | 5 ++--- app/controllers/admin/team_members_controller.rb | 6 +----- app/controllers/admin/users_controller.rb | 16 ++++++---------- app/controllers/admin_controller.rb | 11 +++++++++++ app/controllers/application_controller.rb | 4 ---- 9 files changed, 27 insertions(+), 44 deletions(-) create mode 100644 app/controllers/admin_controller.rb 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 a0040298..5ac5c639 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -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 From a0893b4d58a6162743b325efe0f93b1b957e8a0a Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 10 Aug 2012 18:44:36 -0400 Subject: [PATCH 095/123] Remove non-existent "close" action from authorize_modify_issue filter --- app/controllers/issues_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 3d305238..9be37ca1 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] From 8cfb197dfcad3aa0c11f7afd34e4c7bfef953d1d Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 10 Aug 2012 18:51:07 -0400 Subject: [PATCH 096/123] Remove redundant access check for Issues#destroy We were already calling `authorize_admin_issue!` in a before filter with the same permission checks, so this deleted check wasn't actually doing anything. --- app/controllers/issues_controller.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 9be37ca1..1d78a6d9 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -87,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| From 95bd93fe1aad3efbe2c8cc7b255a98ddb27d2d35 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 16 Sep 2012 09:21:20 -0400 Subject: [PATCH 097/123] Remove Projects#team action Uses TeamMembers#index instead, to be more RESTful --- app/controllers/team_members_controller.rb | 6 +++--- app/helpers/application_helper.rb | 2 +- app/helpers/tab_helper.rb | 2 +- app/views/projects/_project_head.html.haml | 4 ++-- app/views/team_members/_form.html.haml | 2 +- app/views/{projects => team_members}/_team.html.haml | 0 .../team.html.haml => team_members/index.html.haml} | 6 ++---- app/views/team_members/show.html.haml | 2 +- config/routes.rb | 2 +- features/steps/shared/paths.rb | 2 +- spec/routing/routing_spec.rb | 5 ----- 11 files changed, 13 insertions(+), 20 deletions(-) rename app/views/{projects => team_members}/_team.html.haml (100%) rename app/views/{projects/team.html.haml => team_members/index.html.haml} (79%) diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb index 606cb972..27f40b5a 100644 --- a/app/controllers/team_members_controller.rb +++ b/app/controllers/team_members_controller.rb @@ -22,7 +22,7 @@ class TeamMembersController < ApplicationController params[:project_access] ) - redirect_to team_project_path(@project) + redirect_to project_team_index_path(@project) end def update @@ -32,7 +32,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 @@ -40,7 +40,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/helpers/application_helper.rb b/app/helpers/application_helper.rb index 3e435840..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 diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb index 1740864b..b5d7ccb7 100644 --- a/app/helpers/tab_helper.rb +++ b/app/helpers/tab_helper.rb @@ -8,7 +8,7 @@ module TabHelper end def project_tab_class - [:show, :files, :team, :edit, :update].each do |action| + [:show, :files, :edit, :update].each do |action| return "current" if current_page?(controller: "projects", action: action, id: @project) end 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/team_members/_form.html.haml b/app/views/team_members/_form.html.haml index 3736bfea..92167138 100644 --- a/app/views/team_members/_form.html.haml +++ b/app/views/team_members/_form.html.haml @@ -20,4 +20,4 @@ .actions = f.submit 'Save', class: "btn save-btn" - = link_to "Cancel", team_project_path(@project), class: "btn cancel-btn" + = link_to "Cancel", project_team_index_path(@project), class: "btn cancel-btn" diff --git a/app/views/projects/_team.html.haml b/app/views/team_members/_team.html.haml similarity index 100% rename from app/views/projects/_team.html.haml rename to app/views/team_members/_team.html.haml 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 3b5c78a8..9d03cd2c 100644 --- a/app/views/team_members/show.html.haml +++ b/app/views/team_members/show.html.haml @@ -14,7 +14,7 @@ %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 diff --git a/config/routes.rb b/config/routes.rb index c226a473..cfb9bdb9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -90,7 +90,6 @@ Gitlab::Application.routes.draw do # resources :projects, constraints: { id: /[^\/]+/ }, except: [:new, :create, :index], path: "/" do member do - get "team" get "wall" get "graph" get "files" @@ -192,6 +191,7 @@ 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] diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index b0028f9c..93ad0219 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -98,7 +98,7 @@ module SharedPaths end Then 'I visit project "Shop" team page' do - visit team_project_path(Project.find_by_name("Shop")) + visit project_team_index_path(Project.find_by_name("Shop")) end Then 'I visit project "Shop" wall page' do diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb index f69422ba..c93fb58a 100644 --- a/spec/routing/routing_spec.rb +++ b/spec/routing/routing_spec.rb @@ -227,7 +227,6 @@ end # projects POST /projects(.:format) projects#create # new_project GET /projects/new(.:format) projects#new -# team_project GET /:id/team(.:format) projects#team # wall_project GET /:id/wall(.:format) projects#wall # graph_project GET /:id/graph(.:format) projects#graph # files_project GET /:id/files(.:format) projects#files @@ -244,10 +243,6 @@ describe ProjectsController, "routing" do get("/projects/new").should route_to('projects#new') end - it "to #team" do - get("/gitlabhq/team").should route_to('projects#team', id: 'gitlabhq') - end - it "to #wall" do get("/gitlabhq/wall").should route_to('projects#wall', id: 'gitlabhq') end From 02b24cefc7d48c1a4adb4a3fcd430770022db7b1 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 16 Sep 2012 10:38:01 -0400 Subject: [PATCH 098/123] Missed a use of team_project_path --- spec/requests/security/project_access_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/requests/security/project_access_spec.rb b/spec/requests/security/project_access_spec.rb index 0cdf43bf..af0d5fcd 100644 --- a/spec/requests/security/project_access_spec.rb +++ b/spec/requests/security/project_access_spec.rb @@ -70,7 +70,7 @@ describe "Application access" do end describe "GET /project_code/team" do - subject { team_project_path(@project) } + subject { project_team_index_path(@project) } it { should be_allowed_for @u1 } it { should be_allowed_for @u3 } From c23eb4082948322a1b690e0850c09bfc8df81589 Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Sun, 16 Sep 2012 17:52:06 +0300 Subject: [PATCH 099/123] SSH Keys API implemented --- lib/api.rb | 1 + lib/api/entities.rb | 6 ++++ lib/api/keys.rb | 44 ++++++++++++++++++++++++ spec/requests/api/ssh_keys_spec.rb | 55 ++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 lib/api/keys.rb create mode 100644 spec/requests/api/ssh_keys_spec.rb diff --git a/lib/api.rb b/lib/api.rb index be04701c..37e03849 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -17,5 +17,6 @@ module Gitlab mount Projects mount Issues mount Milestones + mount Keys end end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index b50d683f..13a48e12 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -48,5 +48,11 @@ module Gitlab expose :assignee, :author, using: Entities::UserBasic expose :closed, :updated_at, :created_at end + + class Key < Grape::Entity + expose :id, + :title, + :key + end end end diff --git a/lib/api/keys.rb b/lib/api/keys.rb new file mode 100644 index 00000000..96ab7029 --- /dev/null +++ b/lib/api/keys.rb @@ -0,0 +1,44 @@ +module Gitlab + # Keys API + class Keys < Grape::API + before { authenticate! } + resource :keys do + # Get currently authenticated user's keys + # + # Example Request: + # GET /keys + get do + present current_user.keys, with: Entities::Key + 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 /keys + post do + key = current_user.keys.new( + title: params[:title], + key: params[:key] + ) + if key.save + present key, with: Entities::Key + else + not_found! + end + end + # Delete existed ssh key of currently authenticated user + # + # Parameters: + # id (required) - SSH Key ID + # Example Request: + # DELETE /keys/:id + delete "/:id" do + key = current_user.keys.find params[:id] + key.delete + end + end + end +end + diff --git a/spec/requests/api/ssh_keys_spec.rb b/spec/requests/api/ssh_keys_spec.rb new file mode 100644 index 00000000..b8c60377 --- /dev/null +++ b/spec/requests/api/ssh_keys_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper' + +describe Gitlab::Keys do + include ApiHelpers + let(:user) { + user = Factory.create :user + user.reset_authentication_token! + user + } + let(:key) { Factory.create :key, { user: user}} + + describe "GET /keys" do + context "when unauthenticated" do + it "should return authentication error" do + get api("/keys") + response.status.should == 401 + end + end + context "when authenticated" do + it "should return array of ssh keys" do + user.keys << key + user.save + get api("/keys", user) + response.status.should == 200 + json_response.should be_an Array + json_response.first["title"].should == key.title + end + end + end + + describe "POST /keys" do + it "should not create invalid ssh key" do + post api("/keys", user), { title: "invalid key" } + response.status.should == 404 + end + it "should create ssh key" do + key_attrs = Factory.attributes :key + expect { + post api("/keys", user), key_attrs + }.to change{ user.keys.count }.by(1) + end + end + + describe "DELETE /keys/:id" do + it "should delete existed key" do + user.keys << key + user.save + expect { + delete api("/keys/#{key.id}", user) + }.to change{user.keys.count}.by(-1) + end + end + +end + From b24346fa2b246d71b2918e9d3ac3049f7663fb86 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 16 Sep 2012 10:56:32 -0400 Subject: [PATCH 100/123] Fix permissions for TeamMembers#index --- app/controllers/team_members_controller.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb index 27f40b5a..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]) From 87d40fd276ade536e0b6b3019e52c2e1844e47ea Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Sun, 16 Sep 2012 18:21:59 +0300 Subject: [PATCH 101/123] Docs added --- doc/api/README.md | 1 + doc/api/keys.md | 79 ++++++++++++++++++++++++++++++ lib/api/keys.rb | 8 +++ spec/requests/api/ssh_keys_spec.rb | 18 +++++++ 4 files changed, 106 insertions(+) create mode 100644 doc/api/keys.md diff --git a/doc/api/README.md b/doc/api/README.md index 93919b42..9741072c 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -34,3 +34,4 @@ When listing resources you can pass the following parameters: + [Snippets](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/snippets.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) ++ [SSH Keys](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/keys.md) diff --git a/doc/api/keys.md b/doc/api/keys.md new file mode 100644 index 00000000..8106eb8a --- /dev/null +++ b/doc/api/keys.md @@ -0,0 +1,79 @@ +## List keys + +Get a list of currently authenticated user's keys. + +``` +GET /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 key + +Get a single key. + +``` +GET /keys/:id +``` + +Parameters: + ++ `id` (required) - The ID of a key + +```json +{ + "id": 1, + "title" : "Public key" + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 + 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 + soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" + } +``` +## Add key + +Create new key owned by currently authenticated user + +``` +POST /keys +``` + +Parameters: + ++ `title` (required) - new SSH Key ++ `key` (optional) - new SSH key's title + +Will return created key with status `201 Created` on success, or `404 Not +found` on fail. + +## Delete key + +Delete key owned by currently authenticated user + +``` +DELETE /keys/:id +``` + +Parameters: + ++ `id` (required) - key ID + +Will return `200 OK` on success, or `404 Not Found` on fail. + + diff --git a/lib/api/keys.rb b/lib/api/keys.rb index 96ab7029..d58c7caf 100644 --- a/lib/api/keys.rb +++ b/lib/api/keys.rb @@ -10,6 +10,14 @@ module Gitlab get do present current_user.keys, with: Entities::Key end + # Get single key owned by currently authenticated user + # + # Example Request: + # GET /keys/:id + get "/:id" do + key = current_user.keys.find params[:id] + present key, with: Entities::Key + end # Add new ssh key to currently authenticated user # # Parameters: diff --git a/spec/requests/api/ssh_keys_spec.rb b/spec/requests/api/ssh_keys_spec.rb index b8c60377..7fb8c920 100644 --- a/spec/requests/api/ssh_keys_spec.rb +++ b/spec/requests/api/ssh_keys_spec.rb @@ -28,6 +28,20 @@ describe Gitlab::Keys do end end + describe "GET /keys/:id" do + it "should returm single key" do + user.keys << key + user.save + get api("/keys/#{key.id}", user) + response.status.should == 200 + json_response["title"].should == key.title + end + it "should return 404 Not Found within invalid ID" do + get api("/keys/42", user) + response.status.should == 404 + end + end + describe "POST /keys" do it "should not create invalid ssh key" do post api("/keys", user), { title: "invalid key" } @@ -49,6 +63,10 @@ describe Gitlab::Keys do delete api("/keys/#{key.id}", user) }.to change{user.keys.count}.by(-1) end + it "should return 404 Not Found within invalid ID" do + delete api("/keys/42", user) + response.status.should == 404 + end end end From 4247ccd3401b81f654f2203f4b71f0257fd9c569 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 16 Sep 2012 11:53:36 -0400 Subject: [PATCH 102/123] Remove unused project/_refs partial --- app/views/projects/_refs.html.haml | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 app/views/projects/_refs.html.haml diff --git a/app/views/projects/_refs.html.haml b/app/views/projects/_refs.html.haml deleted file mode 100644 index dc1f3a28..00000000 --- a/app/views/projects/_refs.html.haml +++ /dev/null @@ -1,3 +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 chosen" - = hidden_field_tag :destination, destination From 465e40d3a663944b5aacf3e53a63158a7812f219 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 16 Sep 2012 12:07:57 -0400 Subject: [PATCH 103/123] Extract ref switcher into a partial Also moves onchange JS to projects.js.coffee --- app/assets/javascripts/projects.js.coffee | 6 +++++- app/views/commits/_head.html.haml | 7 +------ app/views/refs/_head.html.haml | 5 +---- app/views/shared/_ref_switcher.html.haml | 5 +++++ 4 files changed, 12 insertions(+), 11 deletions(-) create mode 100644 app/views/shared/_ref_switcher.html.haml diff --git a/app/assets/javascripts/projects.js.coffee b/app/assets/javascripts/projects.js.coffee index 14738e14..008fa8e9 100644 --- a/app/assets/javascripts/projects.js.coffee +++ b/app/assets/javascripts/projects.js.coffee @@ -10,11 +10,15 @@ window.Projects = -> $('form #project_default_branch').chosen() disableButtonIfEmptyField '#project_name', '.project-submit' -# Git clone panel switcher $ -> + # 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/views/commits/_head.html.haml b/app/views/commits/_head.html.haml index 5a09d82a..a8111a72 100644 --- a/app/views/commits/_head.html.haml +++ b/app/views/commits/_head.html.haml @@ -1,9 +1,5 @@ %ul.nav.nav-tabs - %li - = form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do - = select_tag "ref", grouped_options_refs, onchange: "$(this.form).trigger('submit');", class: "project-refs-select chosen" - = hidden_field_tag :destination, "commits" - + %li= render partial: 'shared/ref_switcher', locals: {destination: 'commits'} %li{class: "#{'active' if current_page?(project_commits_path(@project)) }"} = link_to project_commits_path(@project) do Commits @@ -20,7 +16,6 @@ Tags %span.badge= @project.repo.tag_count - - if current_page?(project_commits_path(@project)) && current_user.private_token %li.right %span.rss-icon diff --git a/app/views/refs/_head.html.haml b/app/views/refs/_head.html.haml index 94603f0a..3592f573 100644 --- a/app/views/refs/_head.html.haml +++ b/app/views/refs/_head.html.haml @@ -1,9 +1,6 @@ %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 chosen" - = 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 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 From f4b14494ef6abf3d144c28e4af0c20143383e062 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 16 Sep 2012 12:42:52 -0400 Subject: [PATCH 104/123] Move project-related routing specs to their own file --- spec/routing/project_routing_spec.rb | 398 +++++++++++++++++++++++++++ spec/routing/routing_spec.rb | 397 -------------------------- 2 files changed, 398 insertions(+), 397 deletions(-) create mode 100644 spec/routing/project_routing_spec.rb diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb new file mode 100644 index 00000000..b3f9db01 --- /dev/null +++ b/spec/routing/project_routing_spec.rb @@ -0,0 +1,398 @@ +require 'spec_helper' + +# Shared examples for a resource inside a Project +# +# By default it tests all the default REST actions: index, create, new, edit, +# show, update, and destroy. You can remove actions by customizing the +# `actions` variable. +# +# It also expects a `controller` variable to be available which defines both +# the path to the resource as well as the controller name. +# +# Examples +# +# # Default behavior +# it_behaves_like "RESTful project resources" do +# let(:controller) { 'issues' } +# end +# +# # Customizing actions +# it_behaves_like "RESTful project resources" do +# let(:actions) { [:index] } +# let(:controller) { 'issues' } +# end +shared_examples "RESTful project resources" do + let(:actions) { [:index, :create, :new, :edit, :show, :update, :destroy] } + + it "to #index" do + get("/gitlabhq/#{controller}").should route_to("#{controller}#index", project_id: 'gitlabhq') if actions.include?(:index) + end + + it "to #create" do + post("/gitlabhq/#{controller}").should route_to("#{controller}#create", project_id: 'gitlabhq') if actions.include?(:create) + end + + it "to #new" do + get("/gitlabhq/#{controller}/new").should route_to("#{controller}#new", project_id: 'gitlabhq') if actions.include?(:new) + end + + it "to #edit" do + get("/gitlabhq/#{controller}/1/edit").should route_to("#{controller}#edit", project_id: 'gitlabhq', id: '1') if actions.include?(:edit) + end + + it "to #show" do + get("/gitlabhq/#{controller}/1").should route_to("#{controller}#show", project_id: 'gitlabhq', id: '1') if actions.include?(:show) + end + + it "to #update" do + put("/gitlabhq/#{controller}/1").should route_to("#{controller}#update", project_id: 'gitlabhq', id: '1') if actions.include?(:update) + end + + it "to #destroy" do + delete("/gitlabhq/#{controller}/1").should route_to("#{controller}#destroy", project_id: 'gitlabhq', id: '1') if actions.include?(:destroy) + end +end + +# projects POST /projects(.:format) projects#create +# new_project GET /projects/new(.:format) projects#new +# wall_project GET /:id/wall(.:format) projects#wall +# graph_project GET /:id/graph(.:format) projects#graph +# files_project GET /:id/files(.:format) projects#files +# edit_project GET /:id/edit(.:format) projects#edit +# project GET /:id(.:format) projects#show +# PUT /:id(.:format) projects#update +# DELETE /:id(.:format) projects#destroy +describe ProjectsController, "routing" do + it "to #create" do + post("/projects").should route_to('projects#create') + end + + it "to #new" do + get("/projects/new").should route_to('projects#new') + end + + it "to #wall" do + get("/gitlabhq/wall").should route_to('projects#wall', id: 'gitlabhq') + end + + it "to #graph" do + get("/gitlabhq/graph").should route_to('projects#graph', id: 'gitlabhq') + end + + it "to #files" do + get("/gitlabhq/files").should route_to('projects#files', id: 'gitlabhq') + end + + it "to #edit" do + get("/gitlabhq/edit").should route_to('projects#edit', id: 'gitlabhq') + end + + it "to #show" do + get("/gitlabhq").should route_to('projects#show', id: 'gitlabhq') + end + + it "to #update" do + put("/gitlabhq").should route_to('projects#update', id: 'gitlabhq') + end + + it "to #destroy" do + delete("/gitlabhq").should route_to('projects#destroy', id: 'gitlabhq') + end +end + +# pages_project_wikis GET /:project_id/wikis/pages(.:format) wikis#pages +# history_project_wiki GET /:project_id/wikis/:id/history(.:format) wikis#history +# project_wikis POST /:project_id/wikis(.:format) wikis#create +# edit_project_wiki GET /:project_id/wikis/:id/edit(.:format) wikis#edit +# project_wiki GET /:project_id/wikis/:id(.:format) wikis#show +# DELETE /:project_id/wikis/:id(.:format) wikis#destroy +describe WikisController, "routing" do + it "to #pages" do + get("/gitlabhq/wikis/pages").should route_to('wikis#pages', project_id: 'gitlabhq') + end + + it "to #history" do + get("/gitlabhq/wikis/1/history").should route_to('wikis#history', project_id: 'gitlabhq', id: '1') + end + + it_behaves_like "RESTful project resources" do + let(:actions) { [:create, :edit, :show, :destroy] } + let(:controller) { 'wikis' } + end +end + +# branches_project_repository GET /:project_id/repository/branches(.:format) repositories#branches +# tags_project_repository GET /:project_id/repository/tags(.:format) repositories#tags +# archive_project_repository GET /:project_id/repository/archive(.:format) repositories#archive +# project_repository POST /:project_id/repository(.:format) repositories#create +# new_project_repository GET /:project_id/repository/new(.:format) repositories#new +# edit_project_repository GET /:project_id/repository/edit(.:format) repositories#edit +# GET /:project_id/repository(.:format) repositories#show +# PUT /:project_id/repository(.:format) repositories#update +# DELETE /:project_id/repository(.:format) repositories#destroy +describe RepositoriesController, "routing" do + it "to #branches" do + get("/gitlabhq/repository/branches").should route_to('repositories#branches', project_id: 'gitlabhq') + end + + it "to #tags" do + get("/gitlabhq/repository/tags").should route_to('repositories#tags', project_id: 'gitlabhq') + end + + it "to #archive" do + get("/gitlabhq/repository/archive").should route_to('repositories#archive', project_id: 'gitlabhq') + end + + it "to #create" do + post("/gitlabhq/repository").should route_to('repositories#create', project_id: 'gitlabhq') + end + + it "to #new" do + get("/gitlabhq/repository/new").should route_to('repositories#new', project_id: 'gitlabhq') + end + + it "to #edit" do + get("/gitlabhq/repository/edit").should route_to('repositories#edit', project_id: 'gitlabhq') + end + + it "to #show" do + get("/gitlabhq/repository").should route_to('repositories#show', project_id: 'gitlabhq') + end + + it "to #update" do + put("/gitlabhq/repository").should route_to('repositories#update', project_id: 'gitlabhq') + end + + it "to #destroy" do + delete("/gitlabhq/repository").should route_to('repositories#destroy', project_id: 'gitlabhq') + end +end + +# project_deploy_keys GET /:project_id/deploy_keys(.:format) deploy_keys#index +# POST /:project_id/deploy_keys(.:format) deploy_keys#create +# new_project_deploy_key GET /:project_id/deploy_keys/new(.:format) deploy_keys#new +# edit_project_deploy_key GET /:project_id/deploy_keys/:id/edit(.:format) deploy_keys#edit +# project_deploy_key GET /:project_id/deploy_keys/:id(.:format) deploy_keys#show +# PUT /:project_id/deploy_keys/:id(.:format) deploy_keys#update +# DELETE /:project_id/deploy_keys/:id(.:format) deploy_keys#destroy +describe DeployKeysController, "routing" do + it_behaves_like "RESTful project resources" do + let(:controller) { 'deploy_keys' } + end +end + +# project_protected_branches GET /:project_id/protected_branches(.:format) protected_branches#index +# POST /:project_id/protected_branches(.:format) protected_branches#create +# project_protected_branch DELETE /:project_id/protected_branches/:id(.:format) protected_branches#destroy +describe ProtectedBranchesController, "routing" do + it_behaves_like "RESTful project resources" do + let(:actions) { [:index, :create, :destroy] } + let(:controller) { 'protected_branches' } + end +end + +# switch_project_refs GET /:project_id/switch(.:format) refs#switch +# tree_project_ref GET /:project_id/:id/tree(.:format) refs#tree +# logs_tree_project_ref GET /:project_id/:id/logs_tree(.:format) refs#logs_tree +# blob_project_ref GET /:project_id/:id/blob(.:format) refs#blob +# tree_file_project_ref GET /:project_id/:id/tree/:path(.:format) refs#tree +# logs_file_project_ref GET /:project_id/:id/logs_tree/:path(.:format) refs#logs_tree +# blame_file_project_ref GET /:project_id/:id/blame/:path(.:format) refs#blame +describe RefsController, "routing" do + it "to #switch" do + get("/gitlabhq/switch").should route_to('refs#switch', project_id: 'gitlabhq') + end + + it "to #tree" do + get("/gitlabhq/stable/tree").should route_to('refs#tree', project_id: 'gitlabhq', id: 'stable') + get("/gitlabhq/stable/tree/foo/bar/baz").should route_to('refs#tree', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz') + end + + it "to #logs_tree" do + get("/gitlabhq/stable/logs_tree").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable') + get("/gitlabhq/stable/logs_tree/foo/bar/baz").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz') + end + + it "to #blob" do + get("/gitlabhq/stable/blob").should route_to('refs#blob', project_id: 'gitlabhq', id: 'stable') + end + + it "to #blame" do + get("/gitlabhq/stable/blame/foo/bar/baz").should route_to('refs#blame', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz') + end +end + +# diffs_project_merge_request GET /:project_id/merge_requests/:id/diffs(.:format) merge_requests#diffs +# automerge_project_merge_request GET /:project_id/merge_requests/:id/automerge(.:format) merge_requests#automerge +# automerge_check_project_merge_request GET /:project_id/merge_requests/:id/automerge_check(.:format) merge_requests#automerge_check +# raw_project_merge_request GET /:project_id/merge_requests/:id/raw(.:format) merge_requests#raw +# branch_from_project_merge_requests GET /:project_id/merge_requests/branch_from(.:format) merge_requests#branch_from +# branch_to_project_merge_requests GET /:project_id/merge_requests/branch_to(.:format) merge_requests#branch_to +# project_merge_requests GET /:project_id/merge_requests(.:format) merge_requests#index +# POST /:project_id/merge_requests(.:format) merge_requests#create +# new_project_merge_request GET /:project_id/merge_requests/new(.:format) merge_requests#new +# edit_project_merge_request GET /:project_id/merge_requests/:id/edit(.:format) merge_requests#edit +# project_merge_request GET /:project_id/merge_requests/:id(.:format) merge_requests#show +# PUT /:project_id/merge_requests/:id(.:format) merge_requests#update +# DELETE /:project_id/merge_requests/:id(.:format) merge_requests#destroy +describe MergeRequestsController, "routing" do + it "to #diffs" do + get("/gitlabhq/merge_requests/1/diffs").should route_to('merge_requests#diffs', project_id: 'gitlabhq', id: '1') + end + + it "to #automerge" do + get("/gitlabhq/merge_requests/1/automerge").should route_to('merge_requests#automerge', project_id: 'gitlabhq', id: '1') + end + + it "to #automerge_check" do + get("/gitlabhq/merge_requests/1/automerge_check").should route_to('merge_requests#automerge_check', project_id: 'gitlabhq', id: '1') + end + + it "to #raw" do + get("/gitlabhq/merge_requests/1/raw").should route_to('merge_requests#raw', project_id: 'gitlabhq', id: '1') + end + + it "to #branch_from" do + get("/gitlabhq/merge_requests/branch_from").should route_to('merge_requests#branch_from', project_id: 'gitlabhq') + end + + it "to #branch_to" do + get("/gitlabhq/merge_requests/branch_to").should route_to('merge_requests#branch_to', project_id: 'gitlabhq') + end + + it_behaves_like "RESTful project resources" do + let(:controller) { 'merge_requests' } + end +end + +# raw_project_snippet GET /:project_id/snippets/:id/raw(.:format) snippets#raw +# project_snippets GET /:project_id/snippets(.:format) snippets#index +# POST /:project_id/snippets(.:format) snippets#create +# new_project_snippet GET /:project_id/snippets/new(.:format) snippets#new +# edit_project_snippet GET /:project_id/snippets/:id/edit(.:format) snippets#edit +# project_snippet GET /:project_id/snippets/:id(.:format) snippets#show +# PUT /:project_id/snippets/:id(.:format) snippets#update +# DELETE /:project_id/snippets/:id(.:format) snippets#destroy +describe SnippetsController, "routing" do + it "to #raw" do + get("/gitlabhq/snippets/1/raw").should route_to('snippets#raw', project_id: 'gitlabhq', id: '1') + end + + it_behaves_like "RESTful project resources" do + let(:controller) { 'snippets' } + end +end + +# test_project_hook GET /:project_id/hooks/:id/test(.:format) hooks#test +# project_hooks GET /:project_id/hooks(.:format) hooks#index +# POST /:project_id/hooks(.:format) hooks#create +# project_hook DELETE /:project_id/hooks/:id(.:format) hooks#destroy +describe HooksController, "routing" do + it "to #test" do + get("/gitlabhq/hooks/1/test").should route_to('hooks#test', project_id: 'gitlabhq', id: '1') + end + + it_behaves_like "RESTful project resources" do + let(:actions) { [:index, :create, :destroy] } + let(:controller) { 'hooks' } + end +end + +# compare_project_commits GET /:project_id/commits/compare(.:format) commits#compare +# patch_project_commit GET /:project_id/commits/:id/patch(.:format) commits#patch +# project_commits GET /:project_id/commits(.:format) commits#index +# POST /:project_id/commits(.:format) commits#create +# new_project_commit GET /:project_id/commits/new(.:format) commits#new +# edit_project_commit GET /:project_id/commits/:id/edit(.:format) commits#edit +# project_commit GET /:project_id/commits/:id(.:format) commits#show +# PUT /:project_id/commits/:id(.:format) commits#update +# DELETE /:project_id/commits/:id(.:format) commits#destroy +describe CommitsController, "routing" do + it "to #compare" do + get("/gitlabhq/commits/compare").should route_to('commits#compare', project_id: 'gitlabhq') + end + + it "to #patch" do + get("/gitlabhq/commits/1/patch").should route_to('commits#patch', project_id: 'gitlabhq', id: '1') + end + + it_behaves_like "RESTful project resources" do + let(:controller) { 'commits' } + end +end + +# project_team_members GET /:project_id/team_members(.:format) team_members#index +# POST /:project_id/team_members(.:format) team_members#create +# new_project_team_member GET /:project_id/team_members/new(.:format) team_members#new +# edit_project_team_member GET /:project_id/team_members/:id/edit(.:format) team_members#edit +# project_team_member GET /:project_id/team_members/:id(.:format) team_members#show +# PUT /:project_id/team_members/:id(.:format) team_members#update +# DELETE /:project_id/team_members/:id(.:format) team_members#destroy +describe TeamMembersController, "routing" do + it_behaves_like "RESTful project resources" do + let(:controller) { 'team_members' } + end +end + +# project_milestones GET /:project_id/milestones(.:format) milestones#index +# POST /:project_id/milestones(.:format) milestones#create +# new_project_milestone GET /:project_id/milestones/new(.:format) milestones#new +# edit_project_milestone GET /:project_id/milestones/:id/edit(.:format) milestones#edit +# project_milestone GET /:project_id/milestones/:id(.:format) milestones#show +# PUT /:project_id/milestones/:id(.:format) milestones#update +# DELETE /:project_id/milestones/:id(.:format) milestones#destroy +describe MilestonesController, "routing" do + it_behaves_like "RESTful project resources" do + let(:controller) { 'milestones' } + end +end + +# project_labels GET /:project_id/labels(.:format) labels#index +describe LabelsController, "routing" do + it "to #index" do + get("/gitlabhq/labels").should route_to('labels#index', project_id: 'gitlabhq') + end +end + +# sort_project_issues POST /:project_id/issues/sort(.:format) issues#sort +# bulk_update_project_issues POST /:project_id/issues/bulk_update(.:format) issues#bulk_update +# search_project_issues GET /:project_id/issues/search(.:format) issues#search +# project_issues GET /:project_id/issues(.:format) issues#index +# POST /:project_id/issues(.:format) issues#create +# new_project_issue GET /:project_id/issues/new(.:format) issues#new +# edit_project_issue GET /:project_id/issues/:id/edit(.:format) issues#edit +# project_issue GET /:project_id/issues/:id(.:format) issues#show +# PUT /:project_id/issues/:id(.:format) issues#update +# DELETE /:project_id/issues/:id(.:format) issues#destroy +describe IssuesController, "routing" do + it "to #sort" do + post("/gitlabhq/issues/sort").should route_to('issues#sort', project_id: 'gitlabhq') + end + + it "to #bulk_update" do + post("/gitlabhq/issues/bulk_update").should route_to('issues#bulk_update', project_id: 'gitlabhq') + end + + it "to #search" do + get("/gitlabhq/issues/search").should route_to('issues#search', project_id: 'gitlabhq') + end + + it_behaves_like "RESTful project resources" do + let(:controller) { 'issues' } + end +end + +# preview_project_notes POST /:project_id/notes/preview(.:format) notes#preview +# project_notes GET /:project_id/notes(.:format) notes#index +# POST /:project_id/notes(.:format) notes#create +# project_note DELETE /:project_id/notes/:id(.:format) notes#destroy +describe NotesController, "routing" do + it "to #preview" do + post("/gitlabhq/notes/preview").should route_to('notes#preview', project_id: 'gitlabhq') + end + + it_behaves_like "RESTful project resources" do + let(:actions) { [:index, :create, :destroy] } + let(:controller) { 'notes' } + end +end diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb index c93fb58a..cb8dbf37 100644 --- a/spec/routing/routing_spec.rb +++ b/spec/routing/routing_spec.rb @@ -1,58 +1,5 @@ require 'spec_helper' -# Shared examples for a resource inside a Project -# -# By default it tests all the default REST actions: index, create, new, edit, -# show, update, and destroy. You can remove actions by customizing the -# `actions` variable. -# -# It also expects a `controller` variable to be available which defines both -# the path to the resource as well as the controller name. -# -# Examples -# -# # Default behavior -# it_behaves_like "RESTful project resources" do -# let(:controller) { 'issues' } -# end -# -# # Customizing actions -# it_behaves_like "RESTful project resources" do -# let(:actions) { [:index] } -# let(:controller) { 'issues' } -# end -shared_examples "RESTful project resources" do - let(:actions) { [:index, :create, :new, :edit, :show, :update, :destroy] } - - it "to #index" do - get("/gitlabhq/#{controller}").should route_to("#{controller}#index", project_id: 'gitlabhq') if actions.include?(:index) - end - - it "to #create" do - post("/gitlabhq/#{controller}").should route_to("#{controller}#create", project_id: 'gitlabhq') if actions.include?(:create) - end - - it "to #new" do - get("/gitlabhq/#{controller}/new").should route_to("#{controller}#new", project_id: 'gitlabhq') if actions.include?(:new) - end - - it "to #edit" do - get("/gitlabhq/#{controller}/1/edit").should route_to("#{controller}#edit", project_id: 'gitlabhq', id: '1') if actions.include?(:edit) - end - - it "to #show" do - get("/gitlabhq/#{controller}/1").should route_to("#{controller}#show", project_id: 'gitlabhq', id: '1') if actions.include?(:show) - end - - it "to #update" do - put("/gitlabhq/#{controller}/1").should route_to("#{controller}#update", project_id: 'gitlabhq', id: '1') if actions.include?(:update) - end - - it "to #destroy" do - delete("/gitlabhq/#{controller}/1").should route_to("#{controller}#destroy", project_id: 'gitlabhq', id: '1') if actions.include?(:destroy) - end -end - # search GET /search(.:format) search#show describe SearchController, "routing" do it "to #show" do @@ -225,53 +172,6 @@ describe DashboardController, "routing" do end end -# projects POST /projects(.:format) projects#create -# new_project GET /projects/new(.:format) projects#new -# wall_project GET /:id/wall(.:format) projects#wall -# graph_project GET /:id/graph(.:format) projects#graph -# files_project GET /:id/files(.:format) projects#files -# edit_project GET /:id/edit(.:format) projects#edit -# project GET /:id(.:format) projects#show -# PUT /:id(.:format) projects#update -# DELETE /:id(.:format) projects#destroy -describe ProjectsController, "routing" do - it "to #create" do - post("/projects").should route_to('projects#create') - end - - it "to #new" do - get("/projects/new").should route_to('projects#new') - end - - it "to #wall" do - get("/gitlabhq/wall").should route_to('projects#wall', id: 'gitlabhq') - end - - it "to #graph" do - get("/gitlabhq/graph").should route_to('projects#graph', id: 'gitlabhq') - end - - it "to #files" do - get("/gitlabhq/files").should route_to('projects#files', id: 'gitlabhq') - end - - it "to #edit" do - get("/gitlabhq/edit").should route_to('projects#edit', id: 'gitlabhq') - end - - it "to #show" do - get("/gitlabhq").should route_to('projects#show', id: 'gitlabhq') - end - - it "to #update" do - put("/gitlabhq").should route_to('projects#update', id: 'gitlabhq') - end - - it "to #destroy" do - delete("/gitlabhq").should route_to('projects#destroy', id: 'gitlabhq') - end -end - # new_user_session GET /users/sign_in(.:format) devise/sessions#new # user_session POST /users/sign_in(.:format) devise/sessions#create # destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy @@ -284,300 +184,3 @@ end describe "Authentication", "routing" do # pending end - -# pages_project_wikis GET /:project_id/wikis/pages(.:format) wikis#pages -# history_project_wiki GET /:project_id/wikis/:id/history(.:format) wikis#history -# project_wikis POST /:project_id/wikis(.:format) wikis#create -# edit_project_wiki GET /:project_id/wikis/:id/edit(.:format) wikis#edit -# project_wiki GET /:project_id/wikis/:id(.:format) wikis#show -# DELETE /:project_id/wikis/:id(.:format) wikis#destroy -describe WikisController, "routing" do - it "to #pages" do - get("/gitlabhq/wikis/pages").should route_to('wikis#pages', project_id: 'gitlabhq') - end - - it "to #history" do - get("/gitlabhq/wikis/1/history").should route_to('wikis#history', project_id: 'gitlabhq', id: '1') - end - - it_behaves_like "RESTful project resources" do - let(:actions) { [:create, :edit, :show, :destroy] } - let(:controller) { 'wikis' } - end -end - -# branches_project_repository GET /:project_id/repository/branches(.:format) repositories#branches -# tags_project_repository GET /:project_id/repository/tags(.:format) repositories#tags -# archive_project_repository GET /:project_id/repository/archive(.:format) repositories#archive -# project_repository POST /:project_id/repository(.:format) repositories#create -# new_project_repository GET /:project_id/repository/new(.:format) repositories#new -# edit_project_repository GET /:project_id/repository/edit(.:format) repositories#edit -# GET /:project_id/repository(.:format) repositories#show -# PUT /:project_id/repository(.:format) repositories#update -# DELETE /:project_id/repository(.:format) repositories#destroy -describe RepositoriesController, "routing" do - it "to #branches" do - get("/gitlabhq/repository/branches").should route_to('repositories#branches', project_id: 'gitlabhq') - end - - it "to #tags" do - get("/gitlabhq/repository/tags").should route_to('repositories#tags', project_id: 'gitlabhq') - end - - it "to #archive" do - get("/gitlabhq/repository/archive").should route_to('repositories#archive', project_id: 'gitlabhq') - end - - it "to #create" do - post("/gitlabhq/repository").should route_to('repositories#create', project_id: 'gitlabhq') - end - - it "to #new" do - get("/gitlabhq/repository/new").should route_to('repositories#new', project_id: 'gitlabhq') - end - - it "to #edit" do - get("/gitlabhq/repository/edit").should route_to('repositories#edit', project_id: 'gitlabhq') - end - - it "to #show" do - get("/gitlabhq/repository").should route_to('repositories#show', project_id: 'gitlabhq') - end - - it "to #update" do - put("/gitlabhq/repository").should route_to('repositories#update', project_id: 'gitlabhq') - end - - it "to #destroy" do - delete("/gitlabhq/repository").should route_to('repositories#destroy', project_id: 'gitlabhq') - end -end - -# project_deploy_keys GET /:project_id/deploy_keys(.:format) deploy_keys#index -# POST /:project_id/deploy_keys(.:format) deploy_keys#create -# new_project_deploy_key GET /:project_id/deploy_keys/new(.:format) deploy_keys#new -# edit_project_deploy_key GET /:project_id/deploy_keys/:id/edit(.:format) deploy_keys#edit -# project_deploy_key GET /:project_id/deploy_keys/:id(.:format) deploy_keys#show -# PUT /:project_id/deploy_keys/:id(.:format) deploy_keys#update -# DELETE /:project_id/deploy_keys/:id(.:format) deploy_keys#destroy -describe DeployKeysController, "routing" do - it_behaves_like "RESTful project resources" do - let(:controller) { 'deploy_keys' } - end -end - -# project_protected_branches GET /:project_id/protected_branches(.:format) protected_branches#index -# POST /:project_id/protected_branches(.:format) protected_branches#create -# project_protected_branch DELETE /:project_id/protected_branches/:id(.:format) protected_branches#destroy -describe ProtectedBranchesController, "routing" do - it_behaves_like "RESTful project resources" do - let(:actions) { [:index, :create, :destroy] } - let(:controller) { 'protected_branches' } - end -end - -# switch_project_refs GET /:project_id/switch(.:format) refs#switch -# tree_project_ref GET /:project_id/:id/tree(.:format) refs#tree -# logs_tree_project_ref GET /:project_id/:id/logs_tree(.:format) refs#logs_tree -# blob_project_ref GET /:project_id/:id/blob(.:format) refs#blob -# tree_file_project_ref GET /:project_id/:id/tree/:path(.:format) refs#tree -# logs_file_project_ref GET /:project_id/:id/logs_tree/:path(.:format) refs#logs_tree -# blame_file_project_ref GET /:project_id/:id/blame/:path(.:format) refs#blame -describe RefsController, "routing" do - it "to #switch" do - get("/gitlabhq/switch").should route_to('refs#switch', project_id: 'gitlabhq') - end - - it "to #tree" do - get("/gitlabhq/stable/tree").should route_to('refs#tree', project_id: 'gitlabhq', id: 'stable') - get("/gitlabhq/stable/tree/foo/bar/baz").should route_to('refs#tree', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz') - end - - it "to #logs_tree" do - get("/gitlabhq/stable/logs_tree").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable') - get("/gitlabhq/stable/logs_tree/foo/bar/baz").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz') - end - - it "to #blob" do - get("/gitlabhq/stable/blob").should route_to('refs#blob', project_id: 'gitlabhq', id: 'stable') - end - - it "to #blame" do - get("/gitlabhq/stable/blame/foo/bar/baz").should route_to('refs#blame', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz') - end -end - -# diffs_project_merge_request GET /:project_id/merge_requests/:id/diffs(.:format) merge_requests#diffs -# automerge_project_merge_request GET /:project_id/merge_requests/:id/automerge(.:format) merge_requests#automerge -# automerge_check_project_merge_request GET /:project_id/merge_requests/:id/automerge_check(.:format) merge_requests#automerge_check -# raw_project_merge_request GET /:project_id/merge_requests/:id/raw(.:format) merge_requests#raw -# branch_from_project_merge_requests GET /:project_id/merge_requests/branch_from(.:format) merge_requests#branch_from -# branch_to_project_merge_requests GET /:project_id/merge_requests/branch_to(.:format) merge_requests#branch_to -# project_merge_requests GET /:project_id/merge_requests(.:format) merge_requests#index -# POST /:project_id/merge_requests(.:format) merge_requests#create -# new_project_merge_request GET /:project_id/merge_requests/new(.:format) merge_requests#new -# edit_project_merge_request GET /:project_id/merge_requests/:id/edit(.:format) merge_requests#edit -# project_merge_request GET /:project_id/merge_requests/:id(.:format) merge_requests#show -# PUT /:project_id/merge_requests/:id(.:format) merge_requests#update -# DELETE /:project_id/merge_requests/:id(.:format) merge_requests#destroy -describe MergeRequestsController, "routing" do - it "to #diffs" do - get("/gitlabhq/merge_requests/1/diffs").should route_to('merge_requests#diffs', project_id: 'gitlabhq', id: '1') - end - - it "to #automerge" do - get("/gitlabhq/merge_requests/1/automerge").should route_to('merge_requests#automerge', project_id: 'gitlabhq', id: '1') - end - - it "to #automerge_check" do - get("/gitlabhq/merge_requests/1/automerge_check").should route_to('merge_requests#automerge_check', project_id: 'gitlabhq', id: '1') - end - - it "to #raw" do - get("/gitlabhq/merge_requests/1/raw").should route_to('merge_requests#raw', project_id: 'gitlabhq', id: '1') - end - - it "to #branch_from" do - get("/gitlabhq/merge_requests/branch_from").should route_to('merge_requests#branch_from', project_id: 'gitlabhq') - end - - it "to #branch_to" do - get("/gitlabhq/merge_requests/branch_to").should route_to('merge_requests#branch_to', project_id: 'gitlabhq') - end - - it_behaves_like "RESTful project resources" do - let(:controller) { 'merge_requests' } - end -end - -# raw_project_snippet GET /:project_id/snippets/:id/raw(.:format) snippets#raw -# project_snippets GET /:project_id/snippets(.:format) snippets#index -# POST /:project_id/snippets(.:format) snippets#create -# new_project_snippet GET /:project_id/snippets/new(.:format) snippets#new -# edit_project_snippet GET /:project_id/snippets/:id/edit(.:format) snippets#edit -# project_snippet GET /:project_id/snippets/:id(.:format) snippets#show -# PUT /:project_id/snippets/:id(.:format) snippets#update -# DELETE /:project_id/snippets/:id(.:format) snippets#destroy -describe SnippetsController, "routing" do - it "to #raw" do - get("/gitlabhq/snippets/1/raw").should route_to('snippets#raw', project_id: 'gitlabhq', id: '1') - end - - it_behaves_like "RESTful project resources" do - let(:controller) { 'snippets' } - end -end - -# test_project_hook GET /:project_id/hooks/:id/test(.:format) hooks#test -# project_hooks GET /:project_id/hooks(.:format) hooks#index -# POST /:project_id/hooks(.:format) hooks#create -# project_hook DELETE /:project_id/hooks/:id(.:format) hooks#destroy -describe HooksController, "routing" do - it "to #test" do - get("/gitlabhq/hooks/1/test").should route_to('hooks#test', project_id: 'gitlabhq', id: '1') - end - - it_behaves_like "RESTful project resources" do - let(:actions) { [:index, :create, :destroy] } - let(:controller) { 'hooks' } - end -end - -# compare_project_commits GET /:project_id/commits/compare(.:format) commits#compare -# patch_project_commit GET /:project_id/commits/:id/patch(.:format) commits#patch -# project_commits GET /:project_id/commits(.:format) commits#index -# POST /:project_id/commits(.:format) commits#create -# new_project_commit GET /:project_id/commits/new(.:format) commits#new -# edit_project_commit GET /:project_id/commits/:id/edit(.:format) commits#edit -# project_commit GET /:project_id/commits/:id(.:format) commits#show -# PUT /:project_id/commits/:id(.:format) commits#update -# DELETE /:project_id/commits/:id(.:format) commits#destroy -describe CommitsController, "routing" do - it "to #compare" do - get("/gitlabhq/commits/compare").should route_to('commits#compare', project_id: 'gitlabhq') - end - - it "to #patch" do - get("/gitlabhq/commits/1/patch").should route_to('commits#patch', project_id: 'gitlabhq', id: '1') - end - - it_behaves_like "RESTful project resources" do - let(:controller) { 'commits' } - end -end - -# project_team_members GET /:project_id/team_members(.:format) team_members#index -# POST /:project_id/team_members(.:format) team_members#create -# new_project_team_member GET /:project_id/team_members/new(.:format) team_members#new -# edit_project_team_member GET /:project_id/team_members/:id/edit(.:format) team_members#edit -# project_team_member GET /:project_id/team_members/:id(.:format) team_members#show -# PUT /:project_id/team_members/:id(.:format) team_members#update -# DELETE /:project_id/team_members/:id(.:format) team_members#destroy -describe TeamMembersController, "routing" do - it_behaves_like "RESTful project resources" do - let(:controller) { 'team_members' } - end -end - -# project_milestones GET /:project_id/milestones(.:format) milestones#index -# POST /:project_id/milestones(.:format) milestones#create -# new_project_milestone GET /:project_id/milestones/new(.:format) milestones#new -# edit_project_milestone GET /:project_id/milestones/:id/edit(.:format) milestones#edit -# project_milestone GET /:project_id/milestones/:id(.:format) milestones#show -# PUT /:project_id/milestones/:id(.:format) milestones#update -# DELETE /:project_id/milestones/:id(.:format) milestones#destroy -describe MilestonesController, "routing" do - it_behaves_like "RESTful project resources" do - let(:controller) { 'milestones' } - end -end - -# project_labels GET /:project_id/labels(.:format) labels#index -describe LabelsController, "routing" do - it "to #index" do - get("/gitlabhq/labels").should route_to('labels#index', project_id: 'gitlabhq') - end -end - -# sort_project_issues POST /:project_id/issues/sort(.:format) issues#sort -# bulk_update_project_issues POST /:project_id/issues/bulk_update(.:format) issues#bulk_update -# search_project_issues GET /:project_id/issues/search(.:format) issues#search -# project_issues GET /:project_id/issues(.:format) issues#index -# POST /:project_id/issues(.:format) issues#create -# new_project_issue GET /:project_id/issues/new(.:format) issues#new -# edit_project_issue GET /:project_id/issues/:id/edit(.:format) issues#edit -# project_issue GET /:project_id/issues/:id(.:format) issues#show -# PUT /:project_id/issues/:id(.:format) issues#update -# DELETE /:project_id/issues/:id(.:format) issues#destroy -describe IssuesController, "routing" do - it "to #sort" do - post("/gitlabhq/issues/sort").should route_to('issues#sort', project_id: 'gitlabhq') - end - - it "to #bulk_update" do - post("/gitlabhq/issues/bulk_update").should route_to('issues#bulk_update', project_id: 'gitlabhq') - end - - it "to #search" do - get("/gitlabhq/issues/search").should route_to('issues#search', project_id: 'gitlabhq') - end - - it_behaves_like "RESTful project resources" do - let(:controller) { 'issues' } - end -end - -# preview_project_notes POST /:project_id/notes/preview(.:format) notes#preview -# project_notes GET /:project_id/notes(.:format) notes#index -# POST /:project_id/notes(.:format) notes#create -# project_note DELETE /:project_id/notes/:id(.:format) notes#destroy -describe NotesController, "routing" do - it "to #preview" do - post("/gitlabhq/notes/preview").should route_to('notes#preview', project_id: 'gitlabhq') - end - - it_behaves_like "RESTful project resources" do - let(:actions) { [:index, :create, :destroy] } - let(:controller) { 'notes' } - end -end From 549c4c2202307608773a10d8ce9a7dc978537de4 Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Sun, 16 Sep 2012 19:51:04 +0300 Subject: [PATCH 105/123] API attributes refactored --- lib/api/helpers.rb | 8 ++++++++ lib/api/issues.rb | 24 ++++++------------------ lib/api/milestones.rb | 18 ++++-------------- lib/api/projects.rb | 38 ++++++++++++++++++-------------------- 4 files changed, 36 insertions(+), 52 deletions(-) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 054eb2d3..d0fc8c43 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -28,6 +28,14 @@ module Gitlab end end + def existed_attributes(keys) + attrs = {} + keys.each do |key| + attrs[key] = params[key] if params[key].present? + end + attrs + end + # error helpers def forbidden! diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 659f065e..b177a4a8 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -48,15 +48,10 @@ 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 = existed_attributes [: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 @@ -81,16 +76,9 @@ module Gitlab @issue = user_project.issues.find(params[:issue_id]) authorize! :modify_issue, @issue - 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) - } - - if @issue.update_attributes(parameters) + attrs = existed_attributes [: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 not_found! diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index 4b0424ba..d5d3347a 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -36,12 +36,8 @@ module Gitlab # Example Request: # POST /projects/:id/milestones post ":id/milestones" do - @milestone = user_project.milestones.new( - title: params[:title], - description: params[:description], - due_date: params[:due_date] - ) - + attrs = existed_attributes [:title, :description, :due_date] + @milestone = user_project.milestones.new attrs if @milestone.save present @milestone, with: Entities::Milestone else @@ -64,14 +60,8 @@ module Gitlab authorize! :admin_milestone, user_project @milestone = user_project.milestones.find(params[:milestone_id]) - parameters = { - title: (params[:title] || @milestone.title), - description: (params[:description] || @milestone.description), - due_date: (params[:due_date] || @milestone.due_date), - closed: (params[:closed] || @milestone.closed) - } - - if @milestone.update_attributes(parameters) + attrs = existed_attributes [:title, :description, :due_date, :closed] + if @milestone.update_attributes attrs present @milestone, with: Entities::Milestone else not_found! diff --git a/lib/api/projects.rb b/lib/api/projects.rb index cf23dc5f..4a263472 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -40,13 +40,16 @@ module Gitlab post do params[:code] ||= params[:name] params[:path] ||= params[:name] - project_attrs = {} - params.each_pair do |k ,v| - if Project.attribute_names.include? k - project_attrs[k] = v - end - end - @project = Project.create_by_user(project_attrs, current_user) + attrs = existed_attributes [: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 @@ -204,12 +207,10 @@ 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] - ) + attrs = existed_attributes [: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 @@ -234,14 +235,11 @@ module Gitlab @snippet = user_project.snippets.find(params[:snippet_id]) authorize! :modify_snippet, @snippet - 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) - } + attrs = existed_attributes [:title, :file_name] + attrs[:expires_at] = params[:lifetime] if params[:lifetime].present? + attrs[:content] = params[:code] if params[:code].present? - if @snippet.update_attributes(parameters) + if @snippet.update_attributes attrs present @snippet, with: Entities::ProjectSnippet else not_found! From b896880eb46c2b8167e2252d3656b5e38e35f6ec Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Sun, 16 Sep 2012 20:08:57 +0300 Subject: [PATCH 106/123] Method name changed --- lib/api/helpers.rb | 2 +- lib/api/issues.rb | 4 ++-- lib/api/milestones.rb | 4 ++-- lib/api/projects.rb | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index d0fc8c43..9a08b995 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -28,7 +28,7 @@ module Gitlab end end - def existed_attributes(keys) + def attributes_for_keys(keys) attrs = {} keys.each do |key| attrs[key] = params[key] if params[key].present? diff --git a/lib/api/issues.rb b/lib/api/issues.rb index b177a4a8..4ee2d11f 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -48,7 +48,7 @@ module Gitlab # Example Request: # POST /projects/:id/issues post ":id/issues" do - attrs = existed_attributes [:title, :description, :assignee_id, :milestone_id] + 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 @@ -76,7 +76,7 @@ module Gitlab @issue = user_project.issues.find(params[:issue_id]) authorize! :modify_issue, @issue - attrs = existed_attributes [:title, :description, :assignee_id, :milestone_id, :closed] + 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 diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index d5d3347a..daaff940 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -36,7 +36,7 @@ module Gitlab # Example Request: # POST /projects/:id/milestones post ":id/milestones" do - attrs = existed_attributes [:title, :description, :due_date] + attrs = attributes_for_keys [:title, :description, :due_date] @milestone = user_project.milestones.new attrs if @milestone.save present @milestone, with: Entities::Milestone @@ -60,7 +60,7 @@ module Gitlab authorize! :admin_milestone, user_project @milestone = user_project.milestones.find(params[:milestone_id]) - attrs = existed_attributes [:title, :description, :due_date, :closed] + attrs = attributes_for_keys [:title, :description, :due_date, :closed] if @milestone.update_attributes attrs present @milestone, with: Entities::Milestone else diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 4a263472..1d9004f8 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -40,7 +40,7 @@ module Gitlab post do params[:code] ||= params[:name] params[:path] ||= params[:name] - attrs = existed_attributes [:code, + attrs = attributes_for_keys [:code, :path, :name, :description, @@ -207,7 +207,7 @@ module Gitlab # Example Request: # POST /projects/:id/snippets post ":id/snippets" do - attrs = existed_attributes [:title, :file_name] + 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 @@ -235,7 +235,7 @@ module Gitlab @snippet = user_project.snippets.find(params[:snippet_id]) authorize! :modify_snippet, @snippet - attrs = existed_attributes [:title, :file_name] + attrs = attributes_for_keys [:title, :file_name] attrs[:expires_at] = params[:lifetime] if params[:lifetime].present? attrs[:content] = params[:code] if params[:code].present? From c83af0dfe7b82c355eb115a35bfee2a98146b64d Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Sun, 16 Sep 2012 22:44:20 +0300 Subject: [PATCH 107/123] Uses attributes_for_keys --- lib/api/keys.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/api/keys.rb b/lib/api/keys.rb index d58c7caf..4c302727 100644 --- a/lib/api/keys.rb +++ b/lib/api/keys.rb @@ -26,10 +26,8 @@ module Gitlab # Example Request: # POST /keys post do - key = current_user.keys.new( - title: params[:title], - key: params[:key] - ) + attrs = attributes_for_keys [:title, :key] + key = current_user.keys.new attrs if key.save present key, with: Entities::Key else From aaa916f15c9bde139058888be660705390cc02db Mon Sep 17 00:00:00 2001 From: Saito Date: Mon, 17 Sep 2012 18:36:23 +0800 Subject: [PATCH 108/123] use high level api and compatibility with Passenger --- lib/gitlab/backend/grack_auth.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index 4f77c327..43a75cc3 100644 --- a/lib/gitlab/backend/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 From 9c0f6e87146bd9b55cdf84e546e7645b91f99dda Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Mon, 17 Sep 2012 20:18:49 +0300 Subject: [PATCH 109/123] Small fixes added --- doc/api/keys.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/api/keys.md b/doc/api/keys.md index 8106eb8a..d22b22e2 100644 --- a/doc/api/keys.md +++ b/doc/api/keys.md @@ -44,7 +44,7 @@ Parameters: "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" - } +} ``` ## Add key @@ -56,8 +56,8 @@ POST /keys Parameters: -+ `title` (required) - new SSH Key -+ `key` (optional) - new SSH key's title ++ `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. From 0358c2ebdb7e56694872ceac61f820f39fb2c17b Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Mon, 17 Sep 2012 20:42:18 +0300 Subject: [PATCH 110/123] CONTRIBUTING.md copied from wiki pages --- CONTRIBUTING.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..487aa193 --- /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 + From aeb87d8f1dc9de89e8ff9ff367c8d50e7dc817de Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Mon, 17 Sep 2012 21:38:08 +0300 Subject: [PATCH 111/123] Gitlab => GitLab --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 487aa193..9041530d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ -## Contribute to Gitlab +## Contribute to GitLab -If you want to contribute to Gitlab, follow this process: +If you want to contribute to GitLab, follow this process: 1. Fork the project 2. Create a feature branch @@ -19,7 +19,7 @@ We only accept pull requests if: ## Running tests -To run the specs for Gitlab, you need to run seeds for test db. +To run the specs for GitLab, you need to run seeds for test db. cd gitlabhq rake db:seed_fu RAILS_ENV=test From 249cb19d96cff52f70f930fbf13ee23ae5d66d3e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Sep 2012 08:54:17 +0300 Subject: [PATCH 112/123] Fix project update. Make slim form only for reversed comments --- app/assets/javascripts/notes.js | 15 ++++++++++----- app/assets/stylesheets/sections/notes.scss | 10 ---------- app/views/notes/_common_form.html.haml | 2 +- .../notes/_reversed_notes_with_form.html.haml | 2 +- app/views/projects/edit.html.haml | 6 +++--- 5 files changed, 15 insertions(+), 20 deletions(-) diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 81bb1d6d..4a55b41b 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -34,16 +34,21 @@ var NoteList = { disableButtonIfEmptyField(".note-text", ".submit_note"); - $(".note-text").on("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); }); + + 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(); + }); + } }, diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 148807d6..5fc6c96e 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -10,13 +10,6 @@ padding:0px; } -#new-notes-list:not(.reversed) { - border-top:1px solid #aaa; -} -#new-notes-list.reversed { - border-bottom:1px solid #ccc; -} - .issue_notes, .wiki_notes { .note_content { @@ -33,9 +26,6 @@ } #new_note { - .note-text { - height:40px; - } .attach_holder { display:none; } diff --git a/app/views/notes/_common_form.html.haml b/app/views/notes/_common_form.html.haml index 6d559cfc..fc6e3c7e 100644 --- a/app/views/notes/_common_form.html.haml +++ b/app/views/notes/_common_form.html.haml @@ -14,7 +14,7 @@ .right Comments are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. .clearfix - .row.note_advanced_opts.hide + .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' diff --git a/app/views/notes/_reversed_notes_with_form.html.haml b/app/views/notes/_reversed_notes_with_form.html.haml index 05f01847..24d59924 100644 --- a/app/views/notes/_reversed_notes_with_form.html.haml +++ b/app/views/notes/_reversed_notes_with_form.html.haml @@ -8,4 +8,4 @@ :javascript $(function(){ NoteList.init("#{tid}", "#{tt}", "#{project_notes_path(@project)}"); - }); \ No newline at end of file + }); 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(); }); From 64e76a87aaddf76c3b3a487c5eb39e4490e4724f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Sep 2012 09:17:55 +0300 Subject: [PATCH 113/123] Notes votes: use icons instead of borders. Removed unnecessary padding --- app/assets/stylesheets/common.scss | 12 ++++++++++++ app/assets/stylesheets/sections/notes.scss | 10 +--------- app/views/notes/_note.html.haml | 10 +++++++++- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index fda8d54c..ffabdf8b 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -158,6 +158,18 @@ span.update-author { 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 { diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index e14a0828..267a9b43 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -73,15 +73,7 @@ /* mark vote notes */ .voting_notes .note { - padding: 8px 0 8px 12px; - &.upvote { - padding-left: 8px; - border-left: 4px solid #468847; - } - &.downvote { - padding-left: 8px; - border-left: 4px solid #B94A48; - } + padding: 8px 0; } .notes-status { diff --git a/app/views/notes/_note.html.haml b/app/views/notes/_note.html.haml index 23145f12..5234e55d 100644 --- a/app/views/notes/_note.html.haml +++ b/app/views/notes/_note.html.haml @@ -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 From aaec545a677f08a39a49d40db2e454e57ed72cbe Mon Sep 17 00:00:00 2001 From: randx Date: Tue, 18 Sep 2012 20:50:34 +0300 Subject: [PATCH 114/123] Gitlab styled tabs. Better ref selector --- .../stylesheets/gitlab_bootstrap/common.scss | 24 +++++++++++++++- app/assets/stylesheets/ref_select.scss | 28 +++++++++++++------ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index cd7145c9..f4fbd223 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -33,7 +33,29 @@ .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-tabs > .active > a { font-weight:bold; } +.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; } diff --git a/app/assets/stylesheets/ref_select.scss b/app/assets/stylesheets/ref_select.scss index 5b52e11b..9f66136f 100644 --- a/app/assets/stylesheets/ref_select.scss +++ b/app/assets/stylesheets/ref_select.scss @@ -12,35 +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:300px; } } - .chzn-single { + .chzn-single { @include bg-gray-gradient; - div { + div { background:transparent; border-left:none; } - span { + span { font-weight: normal; } } From 4ecf23d2ad4f401c94fabeb061cc36c487276d33 Mon Sep 17 00:00:00 2001 From: randx Date: Tue, 18 Sep 2012 21:05:33 +0300 Subject: [PATCH 115/123] Fix ref select search width --- app/assets/stylesheets/ref_select.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/ref_select.scss b/app/assets/stylesheets/ref_select.scss index 9f66136f..ed6760f1 100644 --- a/app/assets/stylesheets/ref_select.scss +++ b/app/assets/stylesheets/ref_select.scss @@ -38,7 +38,7 @@ } .chzn-search input { - min-width:300px; + min-width:365px; } } From bfed07ee20d5df75e444994912edda48839acbac Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 18 Sep 2012 21:45:09 -0400 Subject: [PATCH 116/123] Add an initializer to allow custom Resque configs --- config/initializers/resque.rb | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 config/initializers/resque.rb 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 From 259ca982da2f2962773ef797fabe6d6641689f5e Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 18 Sep 2012 21:53:27 -0400 Subject: [PATCH 117/123] Add docs for customizing Redis, add example file --- config/resque.yml.example | 3 +++ doc/installation.md | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 config/resque.yml.example 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/doc/installation.md b/doc/installation.md index 345d801d..865cde3c 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -251,6 +251,14 @@ You can login via web using admin generated with setup: # 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 things that should be done ** @@ -276,7 +284,6 @@ You can login via web using admin generated with setup: # of the host serving GitLab. sudo vim /etc/nginx/sites-enabled/gitlab - # Restart nginx: /etc/init.d/nginx restart From bf625b7c92d5f07516339f53fdf391185df8547c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 19 Sep 2012 09:14:07 +0300 Subject: [PATCH 118/123] polishing UI a bit. Added footer links for dashboard --- app/assets/stylesheets/common.scss | 20 +++++++ .../stylesheets/gitlab_bootstrap/common.scss | 10 ++++ app/assets/stylesheets/sections/issues.scss | 55 ++++++++++--------- .../stylesheets/sections/merge_requests.scss | 55 +++++++++---------- app/views/admin/resque/show.html.haml | 6 +- app/views/dashboard/index.html.haml | 8 ++- app/views/events/_event_last_push.html.haml | 2 +- app/views/issues/_show.html.haml | 2 +- app/views/issues/index.html.haml | 2 +- app/views/labels/_label.html.haml | 9 ++- app/views/search/show.html.haml | 19 ++++--- 11 files changed, 117 insertions(+), 71 deletions(-) diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index ffabdf8b..c5b37916 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -145,6 +145,19 @@ span.update-author { .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; @@ -722,3 +735,10 @@ li.note { padding: 6px 20px; margin-right: 12px; } + +.gitlab-promo { + a { + color:#aaa; + margin-right: 30px; + } +} diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index f4fbd223..b9459ee6 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -72,3 +72,13 @@ 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/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss index 230a7aea..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,8 +59,8 @@ input.check_all_issues { height: 22px; } -.issues_content { - .title { +.issues_content { + .title { height: 40px; } } @@ -70,30 +70,30 @@ input.check_all_issues { @media (min-width: 1200px) { .issues_filters select { width:220px; } } -#issues-table-holder { - .issues_filters { - form { +#issues-table-holder { + .issues_filters { + form { padding:0; margin:0; margin-top:7px } - } + } - .issues_bulk_update { + .issues_bulk_update { margin: 0; - form { + form { padding:0; margin:0; margin-top:7px } - .update_selected_issues { + .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; @@ -101,10 +101,11 @@ input.check_all_issues { } } -#update_status { +#update_status { width:100px; } + /** * Milestones list * diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss index 73171915..c932f0fc 100644 --- a/app/assets/stylesheets/sections/merge_requests.scss +++ b/app/assets/stylesheets/sections/merge_requests.scss @@ -1,13 +1,13 @@ -/** +/** * MR form * */ -.mr_branch_box { +.mr_branch_box { @extend .ui-box; margin-bottom:20px; - .body { + .body { background:#f1f1f1; } @@ -17,19 +17,19 @@ * 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; @@ -37,29 +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; @@ -67,19 +67,19 @@ } } -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; } @@ -88,22 +88,21 @@ li.merge_request { @include round-borders-all(4px); padding:2px 4px; border:none; - font-size:13px; + font-size:14px; background: #474D57; color:#fff; - font-weight:bold; - font-family: monospace; + font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; } -.mr_source_commit, -.mr_target_commit { - .commit { +.mr_source_commit, +.mr_target_commit { + .commit { margin:0; padding:0; padding: 5px; margin-bottom: 5px; .avatar { position:relative } - .row_title { + .row_title { color:#444; } .commit-author-name, @@ -113,12 +112,12 @@ li.merge_request { display:none; } list-style:none; - &:hover { + &:hover { background:none; } } } -.mr_direction_tip { +.mr_direction_tip { margin-top:40px } diff --git a/app/views/admin/resque/show.html.haml b/app/views/admin/resque/show.html.haml index d889a5d0..8850e378 100644 --- a/app/views/admin/resque/show.html.haml +++ b/app/views/admin/resque/show.html.haml @@ -1,2 +1,4 @@ -%h3 Resque -%iframe{src: resque_url, width: 1168, height: 600, style: "border: none"} +%h3.page_title Resque +%br +.ui-box + %iframe{src: resque_url, width: '100%', height: 600, style: "border: none"} diff --git a/app/views/dashboard/index.html.haml b/app/views/dashboard/index.html.haml index e13640fb..791c18e3 100644 --- a/app/views/dashboard/index.html.haml +++ b/app/views/dashboard/index.html.haml @@ -31,13 +31,19 @@ %span= project_last_activity(project) .bottom= paginate @projects, theme: "gitlab" - %hr %div %span.rss-icon = link_to dashboard_path(:atom, { private_token: current_user.private_token }) do = image_tag "rss_ui.png", title: "feed" %strong News Feed + %hr + .gitlab-promo + = link_to "Homepage", "http://gitlabhq.com" + = link_to "Blog", "http://blog.gitlabhq.com" + = link_to "@gitlabhq", "https://twitter.com/gitlabhq" + + - else %h3.nothing_here_message There are no projects you have access to. %br diff --git a/app/views/events/_event_last_push.html.haml b/app/views/events/_event_last_push.html.haml index 66e14936..aa1d28f2 100644 --- a/app/views/events/_event_last_push.html.haml +++ b/app/views/events/_event_last_push.html.haml @@ -2,7 +2,7 @@ .event_lp %div = image_tag gravatar_icon(event.author_email), class: "avatar" - %span Your pushed to + %span Your pushed to = event.ref_type = link_to project_commits_path(event.project, ref: event.ref_name) do %strong= truncate(event.ref_name, length: 28) diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml index 22101aa1..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? diff --git a/app/views/issues/index.html.haml b/app/views/issues/index.html.haml index bc5c86e6..22c34baa 100644 --- a/app/views/issues/index.html.haml +++ b/app/views/issues/index.html.haml @@ -12,7 +12,7 @@ = 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/labels/_label.html.haml b/app/views/labels/_label.html.haml index 32158c20..8a465a9e 100644 --- a/app/views/labels/_label.html.haml +++ b/app/views/labels/_label.html.haml @@ -1,4 +1,9 @@ %li.wll - %strong= label.name + %strong + %i.icon-tag + = label.name .right - %span= pluralize label.count, 'issue' + = link_to project_issues_path(label_name: label.name) do + %strong + = pluralize(label.count, 'issue') + = "»" diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml index b4a38b57..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 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 @@ -15,8 +15,9 @@ .row .span6 %table - %tr - %th Projects + %thead + %tr + %th Projects %tbody - @projects.each do |project| %tr @@ -32,8 +33,9 @@ %h4.nothing_here_message No Projects %br %table - %tr - %th Merge Requests + %thead + %tr + %th Merge Requests %tbody - @merge_requests.each do |merge_request| %tr @@ -50,8 +52,9 @@ %h4.nothing_here_message No Merge Requests .span6 %table - %tr - %th Issues + %thead + %tr + %th Issues %tbody - @issues.each do |issue| %tr From 01974185a1640ed869417131d062b5a2eef620bc Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 19 Sep 2012 12:14:42 -0400 Subject: [PATCH 119/123] Simplify is_within matcher [ci skip] --- spec/support/matchers.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/spec/support/matchers.rb b/spec/support/matchers.rb index cb1dcba3..809453c4 100644 --- a/spec/support/matchers.rb +++ b/spec/support/matchers.rb @@ -73,11 +73,7 @@ module Shoulda::Matchers::ActiveModel class EnsureLengthOfMatcher # Shortcut for is_at_least and is_at_most def is_within(range) - if range.exclude_end? - is_at_least(range.first) && is_at_most(range.last - 1) - else - is_at_least(range.first) && is_at_most(range.last) - end + is_at_least(range.min) && is_at_most(range.max) end end end From 496f88afe10f95a7aa64ea8ab10e57412f827283 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 19 Sep 2012 19:42:26 -0400 Subject: [PATCH 120/123] Escape text passed to gfm by link_to_gfm --- app/helpers/gitlab_markdown_helper.rb | 4 ++-- app/views/commits/_commit_box.html.haml | 4 ++-- spec/helpers/gitlab_markdown_helper_spec.rb | 9 ++++++++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index 511d4628..111982e9 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -12,8 +12,8 @@ module GitlabMarkdownHelper # "outer text gfm ref more outer text"). def link_to_gfm(body, url, html_options = {}) return "" if body.blank? - - gfm_body = gfm(body, html_options) + + gfm_body = gfm(escape_once(body), html_options) gfm_body.gsub!(%r{.*?}m) do |match| "#{match}#{link_to("", url, html_options)[0..-5]}" # "".length +1 diff --git a/app/views/commits/_commit_box.html.haml b/app/views/commits/_commit_box.html.haml index 506f4e09..572337de 100644 --- a/app/views/commits/_commit_box.html.haml +++ b/app/views/commits/_commit_box.html.haml @@ -11,10 +11,10 @@ = link_to tree_project_ref_path(@project, @commit.id), class: "browse-button primary grouped" do %strong Browse Code » %h3.commit-title.page_title - = gfm @commit.title + = gfm escape_once(@commit.title) - if @commit.description.present? %pre.commit-description - = gfm @commit.description + = gfm escape_once(@commit.description) .commit-info .row .span4 diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index 0af33142..a6708a7a 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -292,11 +292,18 @@ describe GitlabMarkdownHelper do actual = link_to_gfm("Fixed in #{commit.id}", commit_path, class: 'foo') actual.should have_selector 'a.gfm.gfm-commit.foo' end + + it "escapes HTML passed in as the body" do + actual = "This is a

test

- see ##{issues[0].id}" + link_to_gfm(actual, commit_path).should match('<h1>test</h1>') + end end describe "#markdown" do 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, commit), title: commit.link_title, class: "gfm gfm-commit "} Nam pulvinar sapien eget odio adipiscing at faucibus orci vestibulum.

\n" + actual = "\n\nLorem ipsum dolor sit amet. #{commit.id} Nam pulvinar sapien eget.\n" + expected = project_commit_path(project, commit) + markdown(actual).should match(expected) end it "should handle references in headers" do From ba72c6f683fc52a3223c45c5044abf1361e059fd Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 19 Sep 2012 20:21:12 -0400 Subject: [PATCH 121/123] Escape text passed directly to gfm --- app/views/events/_commit.html.haml | 2 +- app/views/issues/show.html.haml | 2 +- app/views/merge_requests/show/_mr_box.html.haml | 2 +- app/views/milestones/show.html.haml | 2 +- app/views/repositories/_branch.html.haml | 2 +- app/views/repositories/_feed.html.haml | 2 +- app/views/repositories/tags.html.haml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/views/events/_commit.html.haml b/app/views/events/_commit.html.haml index 1e5c00cb..cb25d831 100644 --- a/app/views/events/_commit.html.haml +++ b/app/views/events/_commit.html.haml @@ -5,4 +5,4 @@ %strong.cdark= commit.author_name – = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16 - = gfm truncate(commit.title, length: 50) rescue "--broken encoding" + = gfm escape_once(truncate(commit.title, length: 50)) rescue "--broken encoding" diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index e7365e10..da2aeac4 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -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 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/milestones/show.html.haml b/app/views/milestones/show.html.haml index 0d6cb2a0..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 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/tags.html.haml b/app/views/repositories/tags.html.haml index 0e870c80..a4114586 100644 --- a/app/views/repositories/tags.html.haml +++ b/app/views/repositories/tags.html.haml @@ -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) From 345c4d2a776c3e30d0c05e5954adbfe4142f3519 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 19 Sep 2012 20:21:35 -0400 Subject: [PATCH 122/123] Update gfm so escaped text is still parsed for references --- lib/gitlab/markdown.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 0a467a8d..9201003e 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -48,8 +48,10 @@ module Gitlab def gfm(text, html_options = {}) return text if text.nil? - # prevents the string supplied through the _text_ argument to be altered - text = text.dup + # 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 From 6104942438c14ec7bd21c6cd5bd995272b3faff6 Mon Sep 17 00:00:00 2001 From: randx Date: Thu, 20 Sep 2012 09:06:12 +0300 Subject: [PATCH 123/123] Sanitize for network graph --- lib/gitlab/graph_commit.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/graph_commit.rb b/lib/gitlab/graph_commit.rb index b9859d79..e14d670e 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::SanitizeHelper + 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] = sanitize(Gitlab::Encode.utf8(message)) h[:login] = author.email h end