From a325211552aa55b9b667c2dcfdc8923797f20c06 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 16 Jun 2016 09:30:38 +0200 Subject: [PATCH 1/3] optimization collaborators of a project --- .../controllers/projects.coffee.erb | 43 +++++++++---------- app/assets/templates/projects/_form.html.erb | 2 +- app/controllers/api/members_controller.rb | 15 ++++--- app/policies/user_policy.rb | 5 +-- 4 files changed, 33 insertions(+), 32 deletions(-) diff --git a/app/assets/javascripts/controllers/projects.coffee.erb b/app/assets/javascripts/controllers/projects.coffee.erb index b9a2f2131..37ccea804 100644 --- a/app/assets/javascripts/controllers/projects.coffee.erb +++ b/app/assets/javascripts/controllers/projects.coffee.erb @@ -24,7 +24,7 @@ # - $state (Ui-Router) [ 'app.public.projects_show', 'app.public.projects_list' ] ## class ProjectsController - constructor: ($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document)-> + constructor: ($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, Diacritics)-> ## Retrieve the list of machines from the server Machine.query().$promise.then (data)-> @@ -140,6 +140,17 @@ class ProjectsController $scope.project.project_steps_attributes.splice(index, 1) + $scope.autoCompleteName = (nameLookup) -> + unless nameLookup + return + asciiName = Diacritics.remove(nameLookup) + + Member.search { query: asciiName }, (users) -> + $scope.matchingMembers = users + , (error)-> + console.error(error) + + ## # Controller used on projects listing page @@ -275,8 +286,8 @@ Application.Controllers.controller "ProjectsController", ["$scope", "$state", 'P ## # Controller used in the project creation page ## -Application.Controllers.controller "NewProjectController", ["$scope", "$state", 'Project', 'Machine', 'Member', 'Component', 'Theme', 'Licence', '$document', 'CSRF' -, ($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, CSRF) -> +Application.Controllers.controller "NewProjectController", ["$scope", "$state", 'Project', 'Machine', 'Member', 'Component', 'Theme', 'Licence', '$document', 'CSRF', 'Diacritics' +, ($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, CSRF, Diacritics) -> CSRF.setMetaTags() ## API URL where the form will be posted @@ -290,16 +301,10 @@ Application.Controllers.controller "NewProjectController", ["$scope", "$state", project_steps_attributes: [] project_caos_attributes: [] - ## Other members list (project collaborators) - Member.query().$promise.then (data)-> - $scope.members = data.filter (m) -> - m.id != $scope.currentUser.id - .map (d) -> - id: d.id - name: d.name + $scope.matchingMembers = [] ## Using the ProjectsController - new ProjectsController($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document) + new ProjectsController($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, Diacritics) ] @@ -307,8 +312,8 @@ Application.Controllers.controller "NewProjectController", ["$scope", "$state", ## # Controller used in the project edition page ## -Application.Controllers.controller "EditProjectController", ["$scope", "$state", '$stateParams', 'Project', 'Machine', 'Member', 'Component', 'Theme', 'Licence', '$document', 'CSRF', 'projectPromise' -, ($scope, $state, $stateParams, Project, Machine, Member, Component, Theme, Licence, $document, CSRF, projectPromise) -> +Application.Controllers.controller "EditProjectController", ["$scope", "$state", '$stateParams', 'Project', 'Machine', 'Member', 'Component', 'Theme', 'Licence', '$document', 'CSRF', 'projectPromise', 'Diacritics' +, ($scope, $state, $stateParams, Project, Machine, Member, Component, Theme, Licence, $document, CSRF, projectPromise, Diacritics) -> CSRF.setMetaTags() ## API URL where the form will be posted @@ -320,16 +325,10 @@ Application.Controllers.controller "EditProjectController", ["$scope", "$state", ## Retrieve the project's details, if an error occured, redirect the user to the projects list page $scope.project = projectPromise - ## Other members list (project collaborators) - Member.query().$promise.then (data)-> - $scope.members = data.filter (m) -> - m.id != $scope.project.author_id - .map (d) -> - id: d.id - name: d.name + $scope.matchingMembers = [] - ## Using the ProjectsController - new ProjectsController($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document) + ## Using the ProjectsController + new ProjectsController($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, Diacritics) ] diff --git a/app/assets/templates/projects/_form.html.erb b/app/assets/templates/projects/_form.html.erb index 4dbecba73..4279ca290 100644 --- a/app/assets/templates/projects/_form.html.erb +++ b/app/assets/templates/projects/_form.html.erb @@ -171,7 +171,7 @@ - + diff --git a/app/controllers/api/members_controller.rb b/app/controllers/api/members_controller.rb index 3a31cbcb7..048b37815 100644 --- a/app/controllers/api/members_controller.rb +++ b/app/controllers/api/members_controller.rb @@ -180,7 +180,6 @@ class API::MembersController < API::ApiController end def search - authorize User if params[:subscription] subscription = (params[:subscription] === 'true') @@ -191,10 +190,16 @@ class API::MembersController < API::ApiController .where("users.is_active = 'true' AND roles.name = 'member'") .where("lower(f_unaccent(profiles.first_name)) LIKE ('%' || lower(f_unaccent(:search)) || '%') OR lower(f_unaccent(profiles.last_name)) LIKE ('%' || lower(f_unaccent(:search)) || '%')", search: params[:query]) - if params[:subscription] === 'true' - @members = @members.where('subscriptions.id IS NOT NULL AND subscriptions.expired_at >= :now', now: Date.today.to_s) - elsif params[:subscription] === 'false' - @members = @members.where('subscriptions.id IS NULL OR subscriptions.expired_at < :now', now: Date.today.to_s) + if current_user.is_member? + # non-admin can only retrieve users with "public profiles" + @members = @members.where("users.is_allow_contact = 'true'") + else + # only admins have the ability to filter by subscription + if params[:subscription] === 'true' + @members = @members.where('subscriptions.id IS NOT NULL AND subscriptions.expired_at >= :now', now: Date.today.to_s) + elsif params[:subscription] === 'false' + @members = @members.where('subscriptions.id IS NULL OR subscriptions.expired_at < :now', now: Date.today.to_s) + end end @members diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb index ec73201f9..f56c3de95 100644 --- a/app/policies/user_policy.rb +++ b/app/policies/user_policy.rb @@ -4,7 +4,7 @@ class UserPolicy < ApplicationPolicy if user.is_admin? scope.includes(:group, :training_credits, :machine_credits, :subscriptions => [:plan => [:credits]], :profile => [:user_avatar]).joins(:roles).where("users.is_active = 'true' AND roles.name = 'member'").order('users.created_at desc') else - scope.includes(:group, :training_credits, :machine_credits, :profile => [:user_avatar]).joins(:roles).where("users.is_active = 'true' AND roles.name = 'member'").where(is_allow_contact: true).order('users.created_at desc') + scope.includes(:profile => [:user_avatar]).joins(:roles).where("users.is_active = 'true' AND roles.name = 'member'").where(is_allow_contact: true).order('users.created_at desc') end end end @@ -33,7 +33,4 @@ class UserPolicy < ApplicationPolicy user.is_admin? end - def search? - user.is_admin? - end end From dbeb0717dfa7d79ca5620736fdbcf4e4c810f731 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 16 Jun 2016 11:10:56 +0200 Subject: [PATCH 2/3] fix show existing collaborator name in project edition --- app/assets/javascripts/controllers/projects.coffee.erb | 4 +++- app/assets/templates/projects/_form.html.erb | 2 +- db/schema.rb | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/controllers/projects.coffee.erb b/app/assets/javascripts/controllers/projects.coffee.erb index 37ccea804..f17b24051 100644 --- a/app/assets/javascripts/controllers/projects.coffee.erb +++ b/app/assets/javascripts/controllers/projects.coffee.erb @@ -325,7 +325,9 @@ Application.Controllers.controller "EditProjectController", ["$scope", "$state", ## Retrieve the project's details, if an error occured, redirect the user to the projects list page $scope.project = projectPromise - $scope.matchingMembers = [] + $scope.matchingMembers = $scope.project.project_users.map (u) -> + id: u.id + name: u.full_name ## Using the ProjectsController new ProjectsController($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, Diacritics) diff --git a/app/assets/templates/projects/_form.html.erb b/app/assets/templates/projects/_form.html.erb index 4279ca290..0f00a6f6a 100644 --- a/app/assets/templates/projects/_form.html.erb +++ b/app/assets/templates/projects/_form.html.erb @@ -171,7 +171,7 @@ - + diff --git a/db/schema.rb b/db/schema.rb index c19f3a0b4..70830f169 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -227,7 +227,7 @@ ActiveRecord::Schema.define(version: 20160613093842) do t.boolean "is_read", default: false t.datetime "created_at" t.datetime "updated_at" - t.string "receiver_type" + t.string "receiver_type", limit: 255 t.boolean "is_send", default: false t.jsonb "meta_data", default: {} end @@ -368,7 +368,7 @@ ActiveRecord::Schema.define(version: 20160613093842) do t.datetime "published_at" end - add_index "projects", ["slug"], name: "index_projects_on_slug", using: :btree + add_index "projects", ["slug"], name: "index_projects_on_slug", unique: true, using: :btree create_table "projects_components", force: :cascade do |t| t.integer "project_id" @@ -438,8 +438,8 @@ ActiveRecord::Schema.define(version: 20160613093842) do t.datetime "updated_at" t.integer "availability_id" t.datetime "ex_start_at" - t.datetime "ex_end_at" t.datetime "canceled_at" + t.datetime "ex_end_at" t.boolean "offered", default: false end @@ -597,6 +597,7 @@ ActiveRecord::Schema.define(version: 20160613093842) do add_index "user_trainings", ["user_id"], name: "index_user_trainings_on_user_id", using: :btree create_table "users", force: :cascade do |t| + t.string "username", limit: 255 t.string "email", limit: 255, default: "", null: false t.string "encrypted_password", limit: 255, default: "", null: false t.string "reset_password_token", limit: 255 @@ -619,7 +620,6 @@ ActiveRecord::Schema.define(version: 20160613093842) do t.boolean "is_allow_contact", default: true t.integer "group_id" t.string "stp_customer_id", limit: 255 - t.string "username", limit: 255 t.string "slug", limit: 255 t.boolean "is_active", default: true t.boolean "invoicing_disabled", default: false From 0339fd8e09605bb6ed73966e39e19cde4977ce58 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 16 Jun 2016 12:55:20 +0200 Subject: [PATCH 3/3] allow multi words search in users autocomplete --- README.md | 4 ++-- app/controllers/api/members_controller.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b9bf7724b..9ac11a31c 100644 --- a/README.md +++ b/README.md @@ -595,8 +595,8 @@ Go to your projects gallery and enjoy seeing your projects available from everyw - Using another DBMS than PostgreSQL is not supported, because of some PostgreSQL specific instructions: - `app/controllers/api/members_controllers.rb@list` is using `ILIKE` - `app/controllers/api/invoices_controllers.rb@list` is using `ILIKE` and `date_trunc()` - - `db/migrate/20160613093842_create_unaccent_function.rb` is using [unaccent](https://www.postgresql.org/docs/current/static/unaccent.html) and [trigram](https://www.postgresql.org/docs/current/static/pgtrgm.html) modules - - `app/controllers/api/members_controllers.rb@search` is using `f_unaccent()` defined in the migration above + - `db/migrate/20160613093842_create_unaccent_function.rb` is using [unaccent](https://www.postgresql.org/docs/current/static/unaccent.html) and [trigram](https://www.postgresql.org/docs/current/static/pgtrgm.html) modules and defines a PL/pgSQL function (`f_unaccent()`) + - `app/controllers/api/members_controllers.rb@search` is using `f_unaccent()` (see above) and `regexp_replace()` ## Related Documentation diff --git a/app/controllers/api/members_controller.rb b/app/controllers/api/members_controller.rb index 048b37815..e915b374b 100644 --- a/app/controllers/api/members_controller.rb +++ b/app/controllers/api/members_controller.rb @@ -188,7 +188,7 @@ class API::MembersController < API::ApiController @members = User.includes(:profile) .joins(:profile, :roles, 'LEFT JOIN "subscriptions" ON "subscriptions"."user_id" = "users"."id"') .where("users.is_active = 'true' AND roles.name = 'member'") - .where("lower(f_unaccent(profiles.first_name)) LIKE ('%' || lower(f_unaccent(:search)) || '%') OR lower(f_unaccent(profiles.last_name)) LIKE ('%' || lower(f_unaccent(:search)) || '%')", search: params[:query]) + .where("lower(f_unaccent(profiles.first_name)) ~ regexp_replace(:search, E'\\\\s+', '|') OR lower(f_unaccent(profiles.last_name)) ~ regexp_replace(:search, E'\\\\s+', '|')", search: params[:query].downcase) if current_user.is_member? # non-admin can only retrieve users with "public profiles"