Skip to content

Commit

Permalink
Merge pull request #1011 from mdeniz/project_refactoring_autocomplete
Browse files Browse the repository at this point in the history
[webui] More Refactoring of the Project Controller
  • Loading branch information
hennevogel committed Aug 4, 2015
2 parents 3ff21dc + 7c6cdbc commit 243bb70
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 112 deletions.
95 changes: 23 additions & 72 deletions src/api/app/controllers/webui/project_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,18 @@ class Webui::ProjectController < Webui::WebuiController

helper 'webui/comment'

before_filter :require_project, :except => [:autocomplete_projects, :autocomplete_incidents,
:clear_failed_comment, :edit_comment_form, :index,
:list, :list_all, :list_simple,
:list_public, :new, :package_buildresult,
:save_new, :save_prjconf,
:rebuild_time_png, :new_incident]
before_filter :set_project, only: [:autocomplete_packages, :autocomplete_repositories,
:subprojects]
# This is the deprecated way of loading WebuiProject
# FIXME: Get rid of "except" clauses, use "only" instead
before_filter :require_project, except: [:autocomplete_projects, :autocomplete_incidents,
:autocomplete_packages, :autocomplete_repositories,
:subprojects,
:clear_failed_comment, :edit_comment_form, :index,
:list, :list_all, :list_simple,
:list_public, :new, :package_buildresult,
:save_new, :save_prjconf,
:rebuild_time_png, :new_incident]
before_filter :load_project_info, :only => [:show, :packages_simple]
before_filter :require_login, :only => [:save_new, :toggle_watch, :delete, :new]
before_filter :require_available_architectures, :only => [:add_repository, :add_repository_from_default_list,
Expand Down Expand Up @@ -89,89 +95,30 @@ def list_simple
end

def autocomplete_projects
required_parameters :term
get_filtered_projectlist params[:term], ''
render json: @projects
render json: Project.autocomplete(params[:term]).not_maintenance_incident.order(:name).pluck(:name)
end

def autocomplete_incidents
required_parameters :term
get_filtered_projectlist params[:term], '', :only_incidents => true
render json: @projects
render json: Project.autocomplete(params[:term]).maintenance_incident.order(:name).pluck(:name)
end

def autocomplete_packages
required_parameters :term
if Package.valid_name?( params[:term] ) or params[:term] == ''
packages=Package.arel_table
render json: @project.api_obj.packages.where(packages[:name].matches("#{params[:term]}%")).limit(100).pluck(:name)
else
render text: '[]'
end
render json: @project.packages.autocomplete(params[:term]).pluck(:name)
end

def autocomplete_repositories
render json: @project.repositories
render json: @project.repositories.pluck(:name)
end

def project_key(a)
a = a.downcase

if a[0..4] == 'home:'
a = 'zz' + a
end
return a
end
private :project_key

def get_filtered_projectlist(filterstring, excludefilter='', opts={})
opts = {:only_incidents => false}.merge(opts)
# remove illegal xpath characters
filterstring.gsub!(/[\[\]\n]/, '')
filterstring.gsub!(/[']/, '&apos;')
filterstring.gsub!(/["]/, '&quot;')
rel = Project.all
projects=Project.arel_table
unless filterstring.blank?
rel = rel.where(projects[:name].matches("#{filterstring}%"))
end
unless excludefilter.blank?
rel = rel.where.not(projects[:name].matches("#{excludefilter}%"))
end
if opts[:only_incidents]
rel = rel.where(kind: 'maintenance_incident')
else
rel = rel.where.not(kind: 'maintenance_incident')
end
@projects = rel.pluck(:name)
@projects = @projects.sort_by { |a| project_key a }
end
private :get_filtered_projectlist

def users
@users = @project.users
@groups = @project.groups
@roles = Role.local_roles
end

def subprojects
@subprojects = Array.new

projects=Project.arel_table
Project.where(projects[:name].matches("#{@project.name}:%")).each do |sub|
@subprojects << sub
end
@subprojects.sort! { |x,y| x.name <=> y.name } # Sort by hash key for better display
@parentprojects = Hash.new
parent_names = @project.name.split ':'
parent_names.each_with_index do |parent, idx|
parent_name = parent_names.slice(0, idx+1).join(':')
unless [@project.name, 'home'].include?( parent_name )
parent_project = WebuiProject.find( parent_name )
@parentprojects[parent_name] = parent_project unless parent_project.blank?
end
end
@parentprojects = @parentprojects.sort # Sort by hash key for better display
@subprojects = @project.subprojects.order(:name)
@parentprojects = @project.ancestors.order(:name)
end

def new
Expand Down Expand Up @@ -926,7 +873,7 @@ def monitor
fill_status_cache

load_local_packages

@packagenames = @packagenames.flatten.uniq.sort

## Filter for PackageNames ####
Expand Down Expand Up @@ -1519,4 +1466,8 @@ def move_path(direction)
flash[:success] = "Path #{params['path_project']}/#{params['path_repository']} moved successfully"
redirect_to :action => :repositories, :project => @project
end

def set_project
@project = Project.find_by(name: params[:project])
end
end
8 changes: 4 additions & 4 deletions src/api/app/helpers/maintenance_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def create_new_maintenance_incident( maintenanceProject, baseProject = nil, requ
mi = nil
tprj = nil
Project.transaction do
mi = MaintenanceIncident.new( :maintenance_db_project => maintenanceProject )
mi = MaintenanceIncident.new( :maintenance_db_project => maintenanceProject )
tprj = Project.create :name => mi.project_name
if baseProject
# copy as much as possible from base project
Expand All @@ -30,7 +30,7 @@ def create_new_maintenance_incident( maintenanceProject, baseProject = nil, requ
tprj.flags.create( :flag => 'access', :status => 'disable')
end
# take over roles from maintenance project
maintenanceProject.relationships.each do |r|
maintenanceProject.relationships.each do |r|
tprj.relationships.create(user: r.user, role: r.role, group: r.group)
end
# set default bugowner if missing
Expand Down Expand Up @@ -259,7 +259,7 @@ def get_updateinfo_id(sourcePackage, targetRepo)

# expand a possible defined update info template in release target of channel
projectFilter = nil
if p = sourcePackage.project.find_parent and p.is_maintenance?
if p = sourcePackage.project.parent and p.is_maintenance?
projectFilter = p.maintained_projects.map{|mp| mp.project}
end
# prefer a channel in the source project to avoid double hits exceptions
Expand Down Expand Up @@ -345,7 +345,7 @@ def instantiate_container(project, opackage, opts={})
arguments="&noservice=1"
arguments << "&requestid=" << opts[:requestid] if opts[:requestid]
arguments << "&comment=" << CGI.escape(opts[:comment]) if opts[:comment]
if opts[:makeoriginolder]
if opts[:makeoriginolder]
# versioned copy
path = pkg.source_path + "?cmd=copy&withvrev=1&oproject=#{CGI.escape(opkg.project.name)}&opackage=#{CGI.escape(opkg.name)}#{arguments}&user=#{CGI.escape(User.current.login)}&comment=initialize+package"
if Package.exists_by_project_and_name(project.name, opkg.name, allow_remote_packages: true)
Expand Down
4 changes: 2 additions & 2 deletions src/api/app/models/owner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def self.find_maintainers(container, filter)
m.rootproject = ''
if cont.is_a? Package
m.project = cont.project.name
m.package = cont.name
m.package = cont.name
else
m.project = cont.name
end
Expand All @@ -268,7 +268,7 @@ def self.find_maintainers(container, filter)
# add maintainers from parent projects
while not project.nil?
add_owners.call(project)
project = project.find_parent
project = project.parent
end
maintainers
end
Expand Down
65 changes: 49 additions & 16 deletions src/api/app/models/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ class ForbiddenError < APIException
after_rollback 'Relationship.discard_cache'
after_initialize :init

has_many :packages, :dependent => :destroy, inverse_of: :project
has_many :packages, :dependent => :destroy, inverse_of: :project do
def autocomplete(search)
where(['lower(packages.name) like lower(?)',"#{search}%"])
end
end
has_many :attribs, :dependent => :destroy
has_many :repositories, :dependent => :destroy, foreign_key: :db_project_id
has_many :messages, :as => :db_object, :dependent => :delete_all
Expand Down Expand Up @@ -76,6 +80,13 @@ class ForbiddenError < APIException

default_scope { where('projects.id not in (?)', Relationship.forbidden_project_ids ) }

scope :maintenance, -> { where("kind = 'maintenance'") }
scope :not_maintenance_incident, -> { where("kind <> 'maintenance_incident'") }
scope :maintenance_incident, -> { where("kind = 'maintenance_incident'") }
scope :maintenance_release, -> { where("kind = 'maintenance_release'") }
scope :home, -> { where("name like 'home:%'") }
scope :not_home, -> { where.not("name like 'home:%'") }

validates :name, presence: true, length: { maximum: 200 }, uniqueness: true
validates :title, length: { maximum: 250 }
validate :valid_name
Expand All @@ -88,6 +99,15 @@ def init
self.kind ||= 'standard' if self.has_attribute? :kind
end

def self.autocomplete(search)
projects = Project.where(["lower(name) like lower(?)", "#{search}%"])
if search.to_s.match(/home:./)
projects.home
else
projects.not_home
end
end

def self.deleted_instance
Project.create_with(title: 'Place holder for a deleted project instance').
find_or_create_by(name: 'deleted')
Expand All @@ -114,6 +134,10 @@ def cleanup_before_destroy
end
end

def subprojects
Project.where("name like '#{name}:%'")
end

def revoke_requests
# Find open requests with 'pro' as source or target and decline/revoke them.
# Revoke if source or decline if target went away, pick the first action that matches to decide...
Expand Down Expand Up @@ -409,7 +433,7 @@ def can_be_deleted?
raise DeleteError.new 'This maintenance project has incident projects and can therefore not be deleted.'
end
end

end

def update_from_xml(xmlhash, force=nil)
Expand Down Expand Up @@ -728,7 +752,7 @@ def write_to_backend
# expire cache
reset_cache
@commit_opts ||= {}

if CONFIG['global_write_through'] && !@commit_opts[:no_backend_write]
login = @commit_opts[:login] || User.current.login
query = { user: login }
Expand Down Expand Up @@ -758,21 +782,30 @@ def attribute_url
"/source/#{CGI.escape(self.name)}/_project/_attribute"
end

# step down through namespaces until a project is found, returns found project or nil
def self.find_parent_for(project_name)
name_parts = project_name.split(/:/)

while name_parts.length > 1
name_parts.pop
project = Project.find_by_name(name_parts.join(':'))
break if project
# Give me the first ancestor of that project
def parent
project = nil
possible_ancestor_names.find do |name|
project = Project.find_by(name: name)
end
project
end

# convenience method for self.find_parent_for
def find_parent
self.class.find_parent_for self.name
# Give me all the projects that are ancestors of that project
def ancestors
Project.where(name: possible_ancestor_names)
end

# Calculate all possible ancestors names for a project
# Ex: home:foo:bar:purr => ["home:foo:bar", "home:foo", "home"]
def possible_ancestor_names
names = name.split(/:/)
possible_projects = []
while names.length > 1
names.pop
possible_projects << names.join(':')
end
possible_projects
end

def to_axml(opts={})
Expand Down Expand Up @@ -830,7 +863,7 @@ def flag_status(default, repo, arch, prj_flags, pkg_flags)
# give out the XML for all repos/arch combos
def expand_flags(pkg = nil)
ret = Hash.new

repos = repositories.not_remote

FlagHelper.flag_types.each do |flag_name|
Expand Down Expand Up @@ -1256,7 +1289,7 @@ def self.valid_name?(name)
return false unless name.kind_of? String
# this length check is duplicated but useful for other uses for this function
return false if name.length > 200 || name.blank?
return false if name =~ %r{^[_\.]}
return false if name =~ %r{^[_\.]}
return false if name =~ %r{::}
return false if name.end_with?(':')
return true if name =~ /\A\w[-+\w\.:]*\z/
Expand Down
8 changes: 4 additions & 4 deletions src/api/app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -558,10 +558,10 @@ def can_create_project?(project_name)
return true if /^home:#{self.login}:/.match( project_name ) and ::Configuration.allow_user_to_create_home_project

return true if has_global_permission? 'create_project'
p = Project.find_parent_for(project_name)
return false if p.nil?
parent_project = Project.new(name: project_name).parent
return false if parent_project.nil?
return true if is_admin?
return has_local_permission?( 'create_project', p)
return has_local_permission?( 'create_project', parent_project)
end

def can_modify_attribute_definition?(object)
Expand Down Expand Up @@ -699,7 +699,7 @@ def has_local_permission?( perm_string, object )
when Project
logger.debug "running local permission check: user #{self.login}, project #{object.name}, permission '#{perm_string}'"
#check permission for given project
parent = object.find_parent
parent = object.parent
when nil
return has_global_permission?(perm_string)
else
Expand Down
4 changes: 2 additions & 2 deletions src/api/app/views/webui/project/subprojects.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
%th Parent project
%th Description
%tbody
- @parentprojects.each do |name, project|
- @parentprojects.each do |project|
%tr
%td= link_to name, :action => 'show', :project => name
%td= link_to project.name, :action => 'show', :project => project.name
%td= project.title

%h3= @pagetitle
Expand Down
Loading

0 comments on commit 243bb70

Please sign in to comment.