diff --git a/app/assets/stylesheets/style.scss b/app/assets/stylesheets/style.scss index b56a5d3c..ca17f04a 100644 --- a/app/assets/stylesheets/style.scss +++ b/app/assets/stylesheets/style.scss @@ -351,7 +351,7 @@ header h1.logo a{ text-indent: -1000em; } -header nav{border-radius: 4px; box-shadow: 0 1px 2px black; width: 294px; margin: auto; +header nav{border-radius: 4px; box-shadow: 0 1px 2px black; width: 392px; margin: auto; background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #595d63), to(#31363e)); background-image: -webkit-linear-gradient(#595d63 6.6%, #31363e); background-image: -moz-linear-gradient(#595d63 6.6%, #31363e); @@ -398,6 +398,7 @@ header nav a span{width: 20px; height: 20px; display: inline-block; background: header nav a.dashboard span{background: url('images.png') no-repeat -161px 0;} header nav a.admin span{background: url('images.png') no-repeat -184px 0;} header nav a.project span{background: url('images.png') no-repeat -209px -1px; top: 7px} +header nav a.issues span{background: url('images.png') no-repeat -209px -1px; top: 7px} header .login-top{float: right; width: 180px; background-image: -webkit-gradient(linear, 0 0, 0 62, color-stop(0.032, #464c56), to(#363c45)); diff --git a/app/controllers/user_issues_controller.rb b/app/controllers/user_issues_controller.rb new file mode 100644 index 00000000..4b2245a4 --- /dev/null +++ b/app/controllers/user_issues_controller.rb @@ -0,0 +1,21 @@ +class UserIssuesController < ApplicationController + before_filter :authenticate_user! + + layout "user" + + respond_to :js, :html + + def index + @user = current_user + @issues = current_user.assigned_issues.opened + + @issues = @issues.includes(:author, :project) + + respond_to do |format| + format.html + format.js + format.atom { render :layout => false } + end + end + +end diff --git a/app/controllers/user_merge_requests_controller.rb b/app/controllers/user_merge_requests_controller.rb new file mode 100644 index 00000000..7b6710d5 --- /dev/null +++ b/app/controllers/user_merge_requests_controller.rb @@ -0,0 +1,9 @@ +class UserMergeRequestsController < ApplicationController + before_filter :authenticate_user! + + layout "user" + + def index + @merge_requests = current_user.assigned_merge_requests + end +end diff --git a/app/helpers/user_issues_helper.rb b/app/helpers/user_issues_helper.rb new file mode 100644 index 00000000..aca7d5b8 --- /dev/null +++ b/app/helpers/user_issues_helper.rb @@ -0,0 +1,2 @@ +module UserIssuesHelper +end diff --git a/app/helpers/user_merge_requests_helper.rb b/app/helpers/user_merge_requests_helper.rb new file mode 100644 index 00000000..6e5db315 --- /dev/null +++ b/app/helpers/user_merge_requests_helper.rb @@ -0,0 +1,3 @@ +module UserMergeRequestsHelper +end + diff --git a/app/models/user.rb b/app/models/user.rb index 8967859d..de0bb637 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -25,6 +25,15 @@ class User < ActiveRecord::Base :foreign_key => :assignee_id, :dependent => :destroy + has_many :merge_requests, + :foreign_key => :author_id, + :dependent => :destroy + + has_many :assigned_merge_requests, + :class_name => "MergeRequest", + :foreign_key => :assignee_id, + :dependent => :destroy + before_create :ensure_authentication_token alias_attribute :private_token, :authentication_token scope :not_in_project, lambda { |project| where("id not in (:ids)", :ids => project.users.map(&:id) ) } diff --git a/app/views/issues/_issues.html.haml b/app/views/issues/_issues.html.haml index eb0cae66..bf863a2d 100644 --- a/app/views/issues/_issues.html.haml +++ b/app/views/issues/_issues.html.haml @@ -1,5 +1,5 @@ - @issues.critical.each do |issue| - = render(:partial => 'show', :locals => {:issue => issue}) + = render(:partial => 'issues/show', :locals => {:issue => issue}) - @issues.non_critical.each do |issue| - = render(:partial => 'show', :locals => {:issue => issue}) + = render(:partial => 'issues/show', :locals => {:issue => issue}) diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml index ecb0afd1..a68659d5 100644 --- a/app/views/issues/_show.html.haml +++ b/app/views/issues/_show.html.haml @@ -1,4 +1,4 @@ -%tr{ :id => dom_id(issue), :class => "issue #{issue.critical ? "critical" : ""}", :url => project_issue_path(@project, issue) } +%tr{ :id => dom_id(issue), :class => "issue #{issue.critical ? "critical" : ""}", :url => project_issue_path(issue.project, issue) } %td %strong.issue-number{:class => sort_class}= "##{issue.id}" %span @@ -6,6 +6,9 @@ %br %br %div.note-author + - if not @project.present? + %strong= issue.project.name + = '-' %strong= issue.assignee.name %cite.cgray = time_ago_in_words(issue.created_at) @@ -17,10 +20,10 @@ .right.action-links - if can? current_user, :write_issue, issue - if issue.closed - = link_to 'Reopen', project_issue_path(@project, issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "cgray", :remote => true + = link_to 'Reopen', project_issue_path(issue.project, issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "cgray", :remote => true - else - = link_to 'Resolve', project_issue_path(@project, issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "cgray", :remote => true + = link_to 'Resolve', project_issue_path(issue.project, issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "cgray", :remote => true - if can? current_user, :write_issue, issue - = link_to 'Edit', edit_project_issue_path(@project, issue), :class => "cgray edit-issue-link", :remote => true + = link_to 'Edit', edit_project_issue_path(issue.project, issue), :class => "cgray edit-issue-link", :remote => true - if can?(current_user, :admin_issue, @project) || issue.author == current_user - = link_to 'Remove', [@project, issue], :confirm => 'Are you sure?', :method => :delete, :remote => true, :class => "cred delete-issue negative", :id => "destroy_issue_#{issue.id}" + = link_to 'Remove', [issue.project, issue], :confirm => 'Are you sure?', :method => :delete, :remote => true, :class => "cred delete-issue negative", :id => "destroy_issue_#{issue.id}" diff --git a/app/views/layouts/_head_panel.html.erb b/app/views/layouts/_head_panel.html.erb index 5ad82ecd..5110c184 100644 --- a/app/views/layouts/_head_panel.html.erb +++ b/app/views/layouts/_head_panel.html.erb @@ -25,6 +25,9 @@ <%= link_to dashboard_path, :class => current_page?(root_path) ? "current dashboard" : "dashboard" do %> Dashboard <% end %> + <%= link_to issues_path, :class => current_page?(issues_path) ? "current issues" : "issues" do %> + Issues + <% end %> <%= link_to projects_path, :class => current_page?(projects_path) ? "current project" : "project" do %> Projects <% end %> diff --git a/app/views/layouts/user.html.haml b/app/views/layouts/user.html.haml new file mode 100644 index 00000000..5a936450 --- /dev/null +++ b/app/views/layouts/user.html.haml @@ -0,0 +1,31 @@ +!!! +%html + %head + %title + GitLab #{" - #{current_user.name}"} + = stylesheet_link_tag "application" + = javascript_include_tag "application" + = csrf_meta_tags + = javascript_tag do + REQ_URI = "#{request.env["REQUEST_URI"]}"; + REQ_REFFER = "#{request.env["HTTP_REFERER"]}"; + %body{ :class => body_class('project-page'), :id => yield(:boyd_id)} + = render :partial => "layouts/flash" + #container + = render :partial => "layouts/head_panel" + .project-container + .project-sidebar + .fixed + %aside + = link_to issues_path, :class => current_page?(issues_path) ? "current" : nil do + Issues + - unless current_user.assigned_issues.empty? + %span{ :class => "number" }= current_user.assigned_issues.count + = link_to merge_requests_path, :class => current_page?(merge_requests_path) ? "current" : nil do + Merge Requests + - unless current_user.assigned_merge_requests.empty? + %span{ :class => "number" }= current_user.assigned_merge_requests.count + + .project-content + = yield + diff --git a/app/views/merge_requests/_merge_request.html.haml b/app/views/merge_requests/_merge_request.html.haml index c5bcf779..ef290833 100644 --- a/app/views/merge_requests/_merge_request.html.haml +++ b/app/views/merge_requests/_merge_request.html.haml @@ -1,8 +1,11 @@ -%a.update-item{:href => project_merge_request_path(@project, merge_request)} +%a.update-item{:href => project_merge_request_path(merge_request.project, merge_request)} = image_tag gravatar_icon(merge_request.author_email), :class => "left", :width => 40 %span.update-title = merge_request.title %span.update-author + - if not @project.present? + %strong= merge_request.project.name + = '-' %strong= merge_request.author_name authored = time_ago_in_words(merge_request.created_at) diff --git a/app/views/user_issues/index.atom.builder b/app/views/user_issues/index.atom.builder new file mode 100644 index 00000000..42fc5245 --- /dev/null +++ b/app/views/user_issues/index.atom.builder @@ -0,0 +1,24 @@ +xml.instruct! +xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do + xml.title "#{@user.name} issues" + xml.link :href => issues_url(:atom, :private_token => @user.private_token), :rel => "self", :type => "application/atom+xml" + xml.link :href => issues_url(:private_token => @user.private_token), :rel => "alternate", :type => "text/html" + xml.id issues_url(:private_token => @user.private_token) + xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any? + + @issues.each do |issue| + xml.entry do + xml.id project_issue_url(issue.project, issue) + xml.link :href => project_issue_url(issue.project, issue) + xml.title truncate(issue.title, :length => 80) + xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") + xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(issue.author_email) + xml.author do |author| + xml.name issue.author_name + xml.email issue.author_email + end + xml.summary issue.title + end + end +end + diff --git a/app/views/user_issues/index.html.haml b/app/views/user_issues/index.html.haml new file mode 100644 index 00000000..bf05ca5e --- /dev/null +++ b/app/views/user_issues/index.html.haml @@ -0,0 +1,9 @@ +%div#issues-table-holder + %table.round-borders#issues-table + %thead + %th + .top_panel_issues + %h2 Issues assigned to me + + = render 'issues/issues' + %br diff --git a/app/views/user_merge_requests/index.html.haml b/app/views/user_merge_requests/index.html.haml new file mode 100644 index 00000000..cf1c4143 --- /dev/null +++ b/app/views/user_merge_requests/index.html.haml @@ -0,0 +1,10 @@ +- if @merge_requests.opened.count > 0 + %div{ :class => "update-data ui-box ui-box-small ui-box-big" } + %h3 + %span.tag.open Open + .data + = render @merge_requests.opened + + .clear + %br + diff --git a/config/routes.rb b/config/routes.rb index ad8b0b31..a49aa7a2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,7 @@ Gitlab::Application.routes.draw do + get "user_issues/index" + get 'tags'=> 'tags#index' get 'tags/:tag' => 'projects#index' @@ -21,6 +23,9 @@ Gitlab::Application.routes.draw do put "profile/edit", :to => "profile#social_update" get "profile", :to => "profile#show" get "dashboard", :to => "dashboard#index" + get "issues", :to => "user_issues#index", :as => "issues" + get "merge_requests", :to => "user_merge_requests#index", :as => "merge_requests" + #get "profile/:id", :to => "profile#show" resources :projects, :only => [:new, :create, :index] diff --git a/db/schema.rb b/db/schema.rb index 17246a61..613b65cb 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -13,18 +13,6 @@ ActiveRecord::Schema.define(:version => 20111207211728) do - create_table "features", :force => true do |t| - t.string "name" - t.string "branch_name" - t.integer "assignee_id" - t.integer "author_id" - t.integer "project_id" - t.datetime "created_at" - t.datetime "updated_at" - t.string "version" - t.integer "status", :default => 0, :null => false - end - create_table "issues", :force => true do |t| t.string "title" t.integer "assignee_id" diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 4e1f1308..3a3ac7c9 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -6,6 +6,8 @@ describe User do it { should have_many(:users_projects) } it { should have_many(:issues) } it { should have_many(:assigned_issues) } + it { should have_many(:merge_requests) } + it { should have_many(:assigned_merge_requests) } end describe "Respond to" do diff --git a/spec/requests/merge_requests_spec.rb b/spec/requests/merge_requests_spec.rb index b03ab219..bdbc8909 100644 --- a/spec/requests/merge_requests_spec.rb +++ b/spec/requests/merge_requests_spec.rb @@ -50,7 +50,7 @@ describe "MergeRequests" do end describe "GET /merge_requests/new" do - before do + before do visit new_project_merge_request_path(project) fill_in "merge_request_title", :with => "Merge Request Title" select "master", :from => "merge_request_source_branch" diff --git a/spec/requests/user_issues_spec.rb b/spec/requests/user_issues_spec.rb new file mode 100644 index 00000000..bd29eae3 --- /dev/null +++ b/spec/requests/user_issues_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper' + +describe "User Issues Dashboard" do + describe "GET /issues" do + before do + + login_as :user + + @project1 = Factory :project, + :path => "project1", + :code => "TEST1" + + @project2 = Factory :project, + :path => "project2", + :code => "TEST2" + + @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 issues_path + end + + subject { page } + + it { should have_content(@issue1.title) } + it { should have_content(@issue1.project.name) } + it { should have_content(@issue1.assignee.name) } + + it { should have_content(@issue2.title) } + it { should have_content(@issue2.project.name) } + it { should have_content(@issue2.assignee.name) } + + it "should render atom feed via private token" do + logout + visit 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) + end + end +end diff --git a/spec/requests/user_merge_requests_spec.rb b/spec/requests/user_merge_requests_spec.rb new file mode 100644 index 00000000..fb47f3dd --- /dev/null +++ b/spec/requests/user_merge_requests_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe "User MergeRequests" do + describe "GET /issues" do + before do + + login_as :user + + @project1 = Factory :project, + :path => "project1", + :code => "TEST1" + + @project2 = Factory :project, + :path => "project2", + :code => "TEST2" + + @project1.add_access(@user, :read, :write) + @project2.add_access(@user, :read, :write) + + @merge_request1 = Factory :merge_request, + :author => @user, + :assignee => @user, + :project => @project1 + + @merge_request2 = Factory :merge_request, + :author => @user, + :assignee => @user, + :project => @project2 + + visit merge_requests_path + end + + subject { page } + + it { should have_content(@merge_request1.title) } + it { should have_content(@merge_request1.project.name) } + it { should have_content(@merge_request1.target_branch) } + it { should have_content(@merge_request1.source_branch) } + it { should have_content(@merge_request1.assignee.name) } + + it { should have_content(@merge_request2.title) } + it { should have_content(@merge_request2.project.name) } + it { should have_content(@merge_request2.target_branch) } + it { should have_content(@merge_request2.source_branch) } + it { should have_content(@merge_request2.assignee.name) } + end +end