diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index e73d208..105241f 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -4,13 +4,19 @@ class Admin::UsersController < Admin::BaseController # GET /admin/users def index - ldap = LdapService.new - @ou = Setting.primary_domain - @pagy, @users = pagy(User.where(ou: @ou).order(cn: :asc)) + ldap = LdapService.new + ou = Setting.primary_domain + + @admins = ldap.search_users(:admin, true, :cn) + @contributors = ldap.search_users(:memberStatus, :contributor, :cn) + @sustainers = ldap.search_users(:memberStatus, :sustainer, :cn) + @pagy, @users = pagy(User.where(ou: ou).order(cn: :asc)) @stats = { - users_confirmed: User.where(ou: @ou).confirmed.count, - users_pending: User.where(ou: @ou).pending.count + users_confirmed: User.where(ou: ou).confirmed.count, + users_pending: User.where(ou: ou).pending.count, + users_contributing: @contributors.size, + users_paying: @sustainers.size } end diff --git a/app/models/concerns/settings/member_settings.rb b/app/models/concerns/settings/member_settings.rb new file mode 100644 index 0000000..09c648b --- /dev/null +++ b/app/models/concerns/settings/member_settings.rb @@ -0,0 +1,10 @@ +module Settings + module MemberSettings + extend ActiveSupport::Concern + + included do + field :member_default_status, type: :string, + default: ENV["MEMBER_DEFAULT_STATUS"].presence + end + end +end diff --git a/app/models/user.rb b/app/models/user.rb index a0c49b0..4479800 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -163,7 +163,21 @@ class User < ApplicationRecord def ldap_entry(reload: false) return @ldap_entry if defined?(@ldap_entry) && !reload - @ldap_entry = ldap.fetch_users(uid: self.cn, ou: self.ou).first + @ldap_entry = ldap.fetch_users(cn: self.cn).first + end + + def add_to_ldap_array(attr_key, ldap_attr, value) + current_entries = ldap_entry[attr_key.to_sym] || [] + new_entries = Array(value).map(&:to_s) + entries = (current_entries + new_entries).uniq.sort + ldap.replace_attribute(dn, ldap_attr.to_sym, entries) + end + + def remove_from_ldap_array(attr_key, ldap_attr, value) + current_entries = ldap_entry[attr_key.to_sym] || [] + entries_to_remove = Array(value).map(&:to_s) + entries = (current_entries - entries_to_remove).uniq.sort + ldap.replace_attribute(dn, ldap_attr.to_sym, entries) end def display_name @@ -220,21 +234,39 @@ class User < ApplicationRecord end def enable_service(service) - current_services = services_enabled - new_services = Array(service).map(&:to_s) - services = (current_services + new_services).uniq.sort - ldap.replace_attribute(dn, :serviceEnabled, services) + add_to_ldap_array :services_enabled, :serviceEnabled, service + ldap_entry(reload: true)[:services_enabled] end def disable_service(service) - current_services = services_enabled - disabled_services = Array(service).map(&:to_s) - services = (current_services - disabled_services).uniq.sort - ldap.replace_attribute(dn, :serviceEnabled, services) + remove_from_ldap_array :services_enabled, :serviceEnabled, service + ldap_entry(reload: true)[:services_enabled] end def disable_all_services - ldap.delete_attribute(dn,:service) + ldap.delete_attribute(dn, :serviceEnabled) + end + + def member_status + ldap_entry[:member_status] || [] + end + + def add_member_status(status) + add_to_ldap_array :member_status, :memberStatus, status + ldap_entry(reload: true)[:member_status] + end + + def remove_member_status(status) + remove_from_ldap_array :member_status, :memberStatus, status + ldap_entry(reload: true)[:member_status] + end + + def is_contributing_member? + member_status.map(&:to_sym).include?(:contributor) + end + + def is_paying_member? + member_status.map(&:to_sym).include?(:sustainer) end private diff --git a/app/services/ldap_service.rb b/app/services/ldap_service.rb index 316a58a..a7e9ff5 100644 --- a/app/services/ldap_service.rb +++ b/app/services/ldap_service.rb @@ -50,19 +50,17 @@ class LdapService < ApplicationService end def fetch_users(args={}) - if args[:ou] - treebase = "ou=#{args[:ou]},cn=users,#{ldap_suffix}" - else - treebase = ldap_config["base"] - end - attributes = %w[ - dn cn uid mail displayName admin serviceEnabled + dn cn uid mail displayName admin serviceEnabled memberStatus mailRoutingAddress mailpassword nostrKey pgpKey ] - filter = Net::LDAP::Filter.eq("uid", args[:uid] || "*") + filter = Net::LDAP::Filter.eq('objectClass', 'person') & + Net::LDAP::Filter.eq("cn", args[:cn] || "*") - entries = client.search(base: treebase, filter: filter, attributes: attributes) + entries = client.search( + base: ldap_config["base"], filter: filter, + attributes: attributes + ) entries.sort_by! { |e| e.cn[0] } entries = entries.collect do |e| { @@ -71,6 +69,7 @@ class LdapService < ApplicationService display_name: e.try(:displayName) ? e.displayName.first : nil, admin: e.try(:admin) ? 'admin' : nil, services_enabled: e.try(:serviceEnabled), + member_status: e.try(:memberStatus), email_maildrop: e.try(:mailRoutingAddress), email_password: e.try(:mailpassword), nostr_key: e.try(:nostrKey) ? e.nostrKey.first : nil, @@ -79,10 +78,20 @@ class LdapService < ApplicationService end end + def search_users(search_attr, value, return_attr) + filter = Net::LDAP::Filter.eq('objectClass', 'person') & + Net::LDAP::Filter.eq(search_attr.to_s, value.to_s) & + Net::LDAP::Filter.present('cn') + entries = client.search( + base: ldap_config["base"], filter: filter, + attributes: [return_attr] + ) + entries.map { |entry| entry[return_attr].first }.compact + end + def fetch_organizations attributes = %w{dn ou description} filter = Net::LDAP::Filter.eq("objectClass", "organizationalUnit") - # filter = Net::LDAP::Filter.eq("objectClass", "*") treebase = "cn=users,#{ldap_suffix}" entries = client.search(base: treebase, filter: filter, attributes: attributes) diff --git a/app/views/admin/users/index.html.erb b/app/views/admin/users/index.html.erb index 830057a..c2521e8 100644 --- a/app/views/admin/users/index.html.erb +++ b/app/views/admin/users/index.html.erb @@ -13,6 +13,16 @@ title: 'Pending', value: @stats[:users_pending], ) %> + <%= render QuickstatsItemComponent.new( + type: :number, + title: 'Contributors', + value: @stats[:users_contributing], + ) %> + <%= render QuickstatsItemComponent.new( + type: :number, + title: 'Sustainers', + value: @stats[:users_paying], + ) %> <% end %> @@ -29,8 +39,12 @@ <% @users.each do |user| %>