[issue #620] Changes in Maintainer db:

*  Added maintainer selection on project page (see TODO in sources);
  *  Added `actual` field to BuildList::Package;
  *  Added rake task to set BuildList::Package.actual field.
     Run it after migration (see TODO in sources);
  *  Packages after publising of BuildList becomes actual;
  *  Added MaintainerPresenter to avoid long method chains.
This commit is contained in:
George Vinogradov 2012-08-24 19:19:26 +04:00
parent 629e227d9a
commit 2fbb72e537
21 changed files with 297 additions and 118 deletions

View File

@ -0,0 +1,23 @@
Rosa.Views.ProjectModifyView = Backbone.View.extend({
initialize: function() {
_.bindAll(this, 'checkboxClick');
this.$checkbox_wrapper = $('#niceCheckbox1');
this._$checkbox = this.$checkbox_wrapper.children('#project_is_package').first();
this.$maintainer_form = $('#maintainer_form');
this.$checkbox_wrapper.on('click', this.checkboxClick);
},
checkboxClick: function() {
if (this._$checkbox.is(':checked')) {
this.$maintainer_form.slideDown();
} else {
this.$maintainer_form.slideUp();
}
},
render: function() {
this.checkboxClick();
}
});

View File

@ -1,5 +1,5 @@
function changeCheck(el) {
var el = el, input = el.find('input[type="checkbox"]');
var input = el.find('input[type="checkbox"]');
if(input.attr("checked")) {
el.css('backgroundPosition', '0 0');
@ -13,7 +13,7 @@ function changeCheck(el) {
}
function startChangeCheck(el) {
var el = el, input = el.find('input[type="checkbox"]');
var input = el.find('input[type="checkbox"]');
if(input.attr('checked')) {
el.css('backgroundPosition', '0 -18px');

View File

@ -11,8 +11,8 @@ class Platforms::MaintainersController < ApplicationController
before_filter :authenticate_external_tracker!, :only => ET_CALLBACKS
def index
# Let's build a relation to query maintainers via 'build_list_packages' table
@maintainers = BuildList::Package.maintainers.where(:platform_id => @platform).order('lower(name) ASC').includes(:project).paginate(:page => params[:page])
@maintainers = BuildList::Package.actual.by_platform(@platform).order('lower(name) ASC')
.includes(:project).paginate(:page => params[:page])
end
# Given platform_id, and the string that contains source or binary package name, or project name, find the email of the assignee of the project that contains the given package under the platform specified.

View File

@ -86,6 +86,15 @@ class Projects::ProjectsController < Projects::BaseController
redirect_to projects_path
end
def autocomplete_maintainers
term = params[:term]
limit = 10
items = User.member_of_project(@project)
.where("users.name ILIKE ? OR users.uname ILIKE ?", "%#{term}%", "%#{term}%")
.limit(limit).map { |u| {:value => u.fullname, :label => u.fullname, :id => u.id} }
render :json => items
end
protected
def prepare_list(projects)

View File

@ -125,7 +125,7 @@ class BuildList < ActiveRecord::Base
end
end
after_transition :on => :published, :do => :set_version_and_tag
after_transition :on => :published, :do => [:set_version_and_tag, :actualize_packages]
event :place_build do
transition :waiting_for_response => :build_pending, :if => lambda { |build_list|
@ -201,6 +201,12 @@ class BuildList < ActiveRecord::Base
save
end
def actualize_packages
ActiveRecord::Base.transaction do
self.packages.each(&:actualize)
end
end
#TODO: Share this checking on product owner.
def can_cancel?
[BUILD_PENDING, BuildServer::PLATFORM_PENDING].include?(status) && bs_id

View File

@ -7,20 +7,29 @@ class BuildList::Package < ActiveRecord::Base
attr_accessible :fullname, :name, :release, :version
validates :build_list_id, :project_id, :platform_id, :fullname, :package_type, :name, :release, :version, :presence => true
validates :build_list_id, :project_id, :platform_id, :fullname,
:package_type, :name, :release, :version,
:presence => true
validates :package_type, :inclusion => PACKAGE_TYPES
# This selects only the latest record for each (platform, "package") pair (by 'latest' we mean it, i.e. the greatest created_at). The "package" is identified by its name and type.
# We select the latest created_at-s, and join the table with itself.
scope :maintainers, joins('join(
select name as j_pn, package_type as j_pt, platform_id as j_plid, max(created_at) as j_ca
from build_list_packages
group by j_pn, j_pt, j_plid
) lastmaints
on j_pn = name and j_pt = package_type and j_plid = platform_id and j_ca = created_at'
)
# Fetches only actual (last publised) packages.
scope :actual, where(:actual => true)
scope :by_platform, lambda {|platform| where(:platform_id => platform) }
scope :by_name, lambda {|name| where(:name => name) }
scope :by_package_type, lambda {|type| where(:package_type => type) }
def assignee
project.owner.assignee
project.maintainer
end
def actualize
ActiveRecord::Base.transaction do
old_pkg = self.class.by_platform(self.platform_id).actual
.by_name(self.name).by_package_type(self.package_type)
old_pkg.update_all(:actual => false) if old_pkg
self.actual = true
self.save
end
end
end

View File

@ -5,6 +5,7 @@ class Project < ActiveRecord::Base
NAME_REGEXP = /[a-zA-Z0-9_\-\+\.]+/
belongs_to :owner, :polymorphic => true, :counter_cache => :own_projects_count
belongs_to :maintainer, :class_name => "User"
has_many :issues, :dependent => :destroy
has_many :labels, :dependent => :destroy
@ -26,7 +27,7 @@ class Project < ActiveRecord::Base
validates :visibility, :presence => true, :inclusion => {:in => VISIBILITIES}
validate { errors.add(:base, :can_have_less_or_equal, :count => MAX_OWN_PROJECTS) if owner.projects.size >= MAX_OWN_PROJECTS }
attr_accessible :name, :description, :visibility, :srpm, :is_package, :default_branch, :has_issues, :has_wiki
attr_accessible :name, :description, :visibility, :srpm, :is_package, :default_branch, :has_issues, :has_wiki, :maintainer_id
attr_readonly :name, :owner_id, :owner_type
scope :recent, order("name ASC")
@ -37,6 +38,7 @@ class Project < ActiveRecord::Base
scope :opened, where(:visibility => 'open')
scope :addable_to_repository, lambda { |repository_id| where("projects.id NOT IN (SELECT project_to_repositories.project_id FROM project_to_repositories WHERE (project_to_repositories.repository_id = #{ repository_id }))") }
before_validation :set_maintainer
after_create :attach_to_personal_repository
has_ancestry :orphan_strategy => :rootify #:adopt not available yet
@ -66,6 +68,19 @@ class Project < ActiveRecord::Base
collaborators + groups.map(&:members).flatten
end
def maintainer_id
self[:maintainer_id] || owner.assignee.id
end
alias_method :maintainer_original, :maintainer
def maintainer
maintainer_original || owner.assignee
end
def maintainer_name
maintainer.fullname
end
def platforms
@platforms ||= repositories.map(&:platform).uniq
end
@ -155,4 +170,9 @@ class Project < ActiveRecord::Base
def attach_to_personal_repository
repositories << self.owner.personal_repository if !repositories.exists?(:id => self.owner.personal_repository)
end
def set_maintainer
maintainer ||= owner.assignee
end
end

View File

@ -52,6 +52,10 @@ class User < ActiveRecord::Base
scope :admin, where(:role => 'admin')
scope :real, where(:role => ['', nil])
scope :member_of_project, lambda {|item|
where "#{table_name}.id IN (?)", item.members.map(&:id).uniq
}
after_create lambda { self.create_notifier }
before_create :ensure_authentication_token

View File

@ -0,0 +1,43 @@
class MaintainerPresenter < ApplicationPresenter
attr_reader :package, :package_link, :package_name, :package_type,
:package_version, :package_release, :package_version_release,
:package_updated_at
attr_reader :maintainer, :maintainer_fullname, :maintainer_email,
:maintainer_link, :maintainer_mail_link
delegate :package_type, :to => :package
[:name, :version, :release, :updated_at].each do |meth|
define_method "package_#{meth}" do
@package.send meth
end
end
[:fullname, :email].each do |meth|
define_method "maintainer_#{meth}" do
@maintainer.send meth
end
end
def initialize(package, opts = {})
@package = package
@maintainer = package.try(:assignee)
end
def package_link
link_to @package.name, @package.project
end
def package_version_release
"#{@package.version}-#{@package.release}"
end
def maintainer_link
link_to @maintainer.fullname, @maintainer
end
def maintainer_email_link
mail_to @maintainer.email, @maintainer.email
end
end

View File

@ -10,9 +10,9 @@
= link_to t("layout.platforms.about"), platform_path(@platform)
%li{:class => (contr == :repositories) ? 'active' : ''}
= link_to t("layout.repositories.list_header"), platform_repositories_path(@platform)
-# Do not show "maintainers" menu item while in testing mode
-#%li{:class => (act == :index && contr == :maintainers) ? 'active' : nil}
= link_to t("layout.platforms.maintainers"), platform_maintainers_path(@platform)
- if can? :read, @platform
%li{:class => (act == :index && contr == :maintainers) ? 'active' : nil}
= link_to t("layout.platforms.maintainers"), platform_maintainers_path(@platform)
- if can? :edit, @platform
%li{:class => (contr == :mass_builds && [:index, :create].include?(act)) ? 'active' : ''}
= link_to t("layout.platforms.mass_build"), platform_mass_builds_path(@platform)

View File

@ -1,22 +1,17 @@
%table#myTable.tablesorter.platform-maintainers{:cellspacing => "0", :cellpadding => "0"}
%thead
%tr
%th.th1= t("activerecord.attributes.maintainer.package_name")
%th.th1= t("activerecord.attributes.maintainer.package_type")
%th.th1= t("activerecord.attributes.maintainer.version")
%th.th1= t("activerecord.models.maintainer")
%th.th1= t("activerecord.attributes.maintainer.updated_at")
%th.centered= t("activerecord.attributes.maintainer.package_name")
%th.centered= t("activerecord.attributes.maintainer.package_type")
%th.centered= t("activerecord.attributes.maintainer.version")
%th.centered{:colspan => 2}= t("activerecord.models.maintainer")
%th.centered= t("activerecord.attributes.maintainer.updated_at")
%tbody
- @maintainers.each do |maintainer|
- MaintainerPresenter.present_collection(@maintainers) do |pr|
%tr{:class => cycle("odd", "even")}
%td
= link_to maintainer.name, maintainer.project
%td
= maintainer.package_type
%td
= "#{maintainer.version}-#{maintainer.release}"
%td
= link_to maintainer.assignee.email, maintainer.assignee
%td
= maintainer.updated_at
%td= pr.package_link
%td= pr.package_type
%td= pr.package_version_release
%td= pr.maintainer_link
%td= pr.maintainer_email_link
%td= pr.package_updated_at

View File

@ -6,7 +6,7 @@
.leftlist= f.label :description, t("activerecord.attributes.project.description"), :class => :label
.rightlist= f.text_area :description, :class => 'text_field', :cols => 80
.both
- if ['new', 'create'].include? controller.action_name
- if [:new, :create].include? controller.action_name
.leftlist= f.label :owner_id, t("activerecord.attributes.project.owner"), :class => :label
.rightlist
= label_tag t("activerecord.attributes.project.who_owns.me")
@ -35,7 +35,11 @@
.both
- if [:edit, :update].include? act
.leftlist= t("activerecord.attributes.project.default_branch")
.rightlist= f.select :default_branch, options_from_collection_for_select(@project.repo.branches, :name, :name, @project.default_branch), :class => 'sel80', :id => 'branch_selector'
.rightlist
= f.select :default_branch,
options_from_collection_for_select(@project.repo.branches,
:name, :name, @project.default_branch),
:class => 'sel80', :id => 'branch_selector'
.both
- if [:edit, :update].include? act
.leftlist
@ -45,7 +49,18 @@
%span#niceCheckbox1.niceCheck-main= f.check_box :is_package#, :class => 'niceCheckbox1'
.forcheck= t("activerecord.attributes.project.is_package")
.both
.both
.both
#maintainer_form{:class => @project.is_package ? '' : 'hidden'}
= f.hidden_field :maintainer_id, :value => @project.maintainer_id
.leftlist
= t("activerecord.attributes.project.maintainer")
.rightlist
-# TODO: Maybe use something like Chosen with filter and prepopulated
-# list of potential maintainers?
= autocomplete_field_tag :maintainer_name, @project.maintainer_name,
project_autocomplete_maintainers_path(@project.owner, @project),
:id_element => '#project_maintainer_id',
:placeholder => @project.maintainer_name
- if [:new, :create].include? act
.leftlist= f.label :srpm, t("activerecord.attributes.project.srpm"), :class => :label
.rightlist= f.file_field :srpm, :class => 'file_field'
@ -54,3 +69,7 @@
\ 
.rightlist= submit_tag t("layout.save"), :class => 'button'
.both
:javascript
$(function() {
( new Rosa.Views.ProjectModifyView ).render();
});

View File

@ -20,5 +20,5 @@ en:
package_type: Type
created_at: First Update
updated_at: Last Update
version: Vers.-rel.
version: Version-Release

View File

@ -20,5 +20,5 @@ ru:
package_type: Тип
created_at: Создан
updated_at: Обновлен
version: Vers.-rel.
version: Версия-Релиз

View File

@ -93,6 +93,7 @@ en:
group: Group
default_branch: Default branch
is_package: Project is a package
maintainer: Maintainer of project
errors:
project:
uname: The name can only use lower case Latin letters (a-z), numbers (0-9) and underscore (_)

View File

@ -93,6 +93,7 @@ ru:
group: Группа
default_branch: Ветка по умолчанию
is_package: Проект является пакетом
maintainer: Майнтейнер проекта
errors:
project:
uname: В имени можно использовать только строчные символы латинского алфавита (a-z), цифры (0-9) и символ нижнего подчеркивания (_)

View File

@ -188,6 +188,7 @@ Rosa::Application.routes.draw do
end
end
# Resource
get '/autocomplete_maintainers' => 'projects#autocomplete_maintainers', :as => :autocomplete_maintainers
get '/modify' => 'projects#edit', :as => :edit_project
put '/' => 'projects#update'
delete '/' => 'projects#destroy'

View File

@ -0,0 +1,9 @@
class AddMaintainerIdToProjects < ActiveRecord::Migration
def self.up
add_column :projects, :maintainer_id, :integer
end
def self.down
remove_column :projects, :maintainer_id
end
end

View File

@ -0,0 +1,10 @@
class AddActualToBuildListPackages < ActiveRecord::Migration
def self.up
add_column :build_list_packages, :actual, :boolean, :default => false
add_index :build_list_packages, [:actual, :platform_id], :name => :actual_platform_packages
end
def self.down
remove_column :build_list_packages, :actual
end
end

View File

@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20120730214052) do
ActiveRecord::Schema.define(:version => 20120822210712) do
create_table "activity_feeds", :force => true do |t|
t.integer "user_id", :null => false
@ -91,10 +91,12 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
t.string "version"
t.string "release"
t.string "package_type"
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.boolean "actual", :default => false
end
add_index "build_list_packages", ["actual", "platform_id"], :name => "actual_platform_packages"
add_index "build_list_packages", ["build_list_id"], :name => "index_build_list_packages_on_build_list_id"
add_index "build_list_packages", ["name", "project_id"], :name => "index_build_list_packages_on_name_and_project_id"
add_index "build_list_packages", ["platform_id"], :name => "index_build_list_packages_on_platform_id"
@ -108,8 +110,8 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
t.integer "project_id"
t.integer "arch_id"
t.datetime "notified_at"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "is_circle", :default => false
t.text "additional_repos"
t.string "name"
@ -139,8 +141,8 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
t.string "commentable_type"
t.integer "user_id"
t.text "body"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.decimal "commentable_id", :precision => 50, :scale => 0
t.integer "project_id"
end
@ -157,8 +159,8 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
t.string "controller"
t.string "action"
t.text "message"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "flash_notifies", :force => true do |t|
@ -170,12 +172,10 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
t.datetime "updated_at", :null => false
end
add_index "projects", ["owner_id"], :name => "index_projects_on_name_and_owner_id_and_owner_type", :unique => true, :case_sensitive => false
create_table "groups", :force => true do |t|
t.integer "owner_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.string "uname"
t.integer "own_projects_count", :default => 0, :null => false
t.text "description"
@ -188,8 +188,8 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
t.string "title"
t.text "body"
t.string "status", :default => "open"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
t.datetime "closed_at"
t.integer "closed_by"
@ -249,8 +249,8 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
t.string "description"
t.string "name", :null => false
t.integer "parent_platform_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "released", :default => false, :null => false
t.integer "owner_id"
t.string "owner_type"
@ -265,16 +265,16 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
t.integer "platform_id"
t.string "login"
t.string "password"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
end
create_table "product_build_lists", :force => true do |t|
t.integer "product_id"
t.integer "status", :default => 2, :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "product_build_lists", ["product_id"], :name => "index_product_build_lists_on_product_id"
@ -282,8 +282,8 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
create_table "products", :force => true do |t|
t.string "name", :null => false
t.integer "platform_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.text "build_script"
t.text "counter"
t.text "ks"
@ -302,8 +302,8 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
t.string "name"
t.string "version"
t.datetime "file_mtime"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.integer "platform_id"
end
@ -312,14 +312,14 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
create_table "project_to_repositories", :force => true do |t|
t.integer "project_id"
t.integer "repository_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "projects", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.integer "owner_id"
t.string "owner_type"
t.string "visibility", :default => "open"
@ -335,6 +335,7 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
t.boolean "is_package", :default => true, :null => false
t.integer "average_build_time", :default => 0, :null => false
t.integer "build_count", :default => 0, :null => false
t.integer "maintainer_id"
end
add_index "projects", ["owner_id"], :name => "index_projects_on_name_and_owner_id_and_owner_type", :unique => true, :case_sensitive => false
@ -345,8 +346,8 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
t.string "token"
t.boolean "approved", :default => false
t.boolean "rejected", :default => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.string "interest"
t.text "more"
end
@ -359,16 +360,16 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
t.string "actor_type"
t.integer "target_id"
t.string "target_type"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.string "role"
end
create_table "repositories", :force => true do |t|
t.string "description", :null => false
t.integer "platform_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.string "name", :null => false
end
@ -379,8 +380,8 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
t.boolean "new_comment_reply", :default => true
t.boolean "new_issue", :default => true
t.boolean "issue_assign", :default => true
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "new_comment_commit_owner", :default => true
t.boolean "new_comment_commit_repo_owner", :default => true
t.boolean "new_comment_commit_commentor", :default => true
@ -389,8 +390,8 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
create_table "subscribes", :force => true do |t|
t.string "subscribeable_type"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "status", :default => true
t.integer "project_id"
t.decimal "subscribeable_id", :precision => 50, :scale => 0
@ -398,13 +399,13 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
create_table "users", :force => true do |t|
t.string "name"
t.string "email", :default => "", :null => false
t.string "encrypted_password", :default => "", :null => false
t.string "email", :default => "", :null => false
t.string "encrypted_password", :limit => 128, :default => "", :null => false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.string "uname"
t.string "role"
t.string "language", :default => "en"
@ -417,14 +418,14 @@ ActiveRecord::Schema.define(:version => 20120730214052) do
t.string "avatar_content_type"
t.integer "avatar_file_size"
t.datetime "avatar_updated_at"
t.integer "failed_attempts", :default => 0
t.integer "failed_attempts", :default => 0
t.string "unlock_token"
t.datetime "locked_at"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "authentication_token"
t.integer "build_priority", :default => 50
t.integer "build_priority", :default => 50
end
add_index "users", ["authentication_token"], :name => "index_users_on_authentication_token"

View File

@ -17,4 +17,32 @@ namespace :buildlist do
say "Outdated BuildLists and MassBuilds was successfully removed"
end
end
namespace :packages do
# TODO Maybe do it in migration, because it's just a single query?
desc 'Actualize packages for all platforms'
task :actualize => :environment do
say "Updating packages"
packages = BuildList::Package.joins( %q{
JOIN (
SELECT
name AS j_pn,
package_type AS j_pt,
platform_id AS j_plid,
MAX(created_at) AS j_ca
FROM
build_list_packages
GROUP BY
j_pn, j_pt, j_plid
) AS lastmaints
ON
j_pn = name
AND j_pt = package_type
AND j_plid = platform_id
AND j_ca = created_at
} ).update_all(:actual => true)
say "'Actual' setted to #{packages} packages"
end
end
end