WIP Add member/contributor status to users
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
4bf6985b87
commit
393f85e45c
@ -5,12 +5,18 @@ class Admin::UsersController < Admin::BaseController
|
|||||||
# GET /admin/users
|
# GET /admin/users
|
||||||
def index
|
def index
|
||||||
ldap = LdapService.new
|
ldap = LdapService.new
|
||||||
@ou = Setting.primary_domain
|
ou = Setting.primary_domain
|
||||||
@pagy, @users = pagy(User.where(ou: @ou).order(cn: :asc))
|
|
||||||
|
@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 = {
|
@stats = {
|
||||||
users_confirmed: User.where(ou: @ou).confirmed.count,
|
users_confirmed: User.where(ou: ou).confirmed.count,
|
||||||
users_pending: User.where(ou: @ou).pending.count
|
users_pending: User.where(ou: ou).pending.count,
|
||||||
|
users_contributing: @contributors.size,
|
||||||
|
users_paying: @sustainers.size
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
10
app/models/concerns/settings/member_settings.rb
Normal file
10
app/models/concerns/settings/member_settings.rb
Normal file
@ -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
|
@ -163,7 +163,21 @@ class User < ApplicationRecord
|
|||||||
|
|
||||||
def ldap_entry(reload: false)
|
def ldap_entry(reload: false)
|
||||||
return @ldap_entry if defined?(@ldap_entry) && !reload
|
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
|
end
|
||||||
|
|
||||||
def display_name
|
def display_name
|
||||||
@ -220,21 +234,39 @@ class User < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def enable_service(service)
|
def enable_service(service)
|
||||||
current_services = services_enabled
|
add_to_ldap_array :services_enabled, :serviceEnabled, service
|
||||||
new_services = Array(service).map(&:to_s)
|
ldap_entry(reload: true)[:services_enabled]
|
||||||
services = (current_services + new_services).uniq.sort
|
|
||||||
ldap.replace_attribute(dn, :serviceEnabled, services)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def disable_service(service)
|
def disable_service(service)
|
||||||
current_services = services_enabled
|
remove_from_ldap_array :services_enabled, :serviceEnabled, service
|
||||||
disabled_services = Array(service).map(&:to_s)
|
ldap_entry(reload: true)[:services_enabled]
|
||||||
services = (current_services - disabled_services).uniq.sort
|
|
||||||
ldap.replace_attribute(dn, :serviceEnabled, services)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def disable_all_services
|
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
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -50,19 +50,17 @@ class LdapService < ApplicationService
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_users(args={})
|
def fetch_users(args={})
|
||||||
if args[:ou]
|
|
||||||
treebase = "ou=#{args[:ou]},cn=users,#{ldap_suffix}"
|
|
||||||
else
|
|
||||||
treebase = ldap_config["base"]
|
|
||||||
end
|
|
||||||
|
|
||||||
attributes = %w[
|
attributes = %w[
|
||||||
dn cn uid mail displayName admin serviceEnabled
|
dn cn uid mail displayName admin serviceEnabled memberStatus
|
||||||
mailRoutingAddress mailpassword nostrKey pgpKey
|
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.sort_by! { |e| e.cn[0] }
|
||||||
entries = entries.collect do |e|
|
entries = entries.collect do |e|
|
||||||
{
|
{
|
||||||
@ -71,6 +69,7 @@ class LdapService < ApplicationService
|
|||||||
display_name: e.try(:displayName) ? e.displayName.first : nil,
|
display_name: e.try(:displayName) ? e.displayName.first : nil,
|
||||||
admin: e.try(:admin) ? 'admin' : nil,
|
admin: e.try(:admin) ? 'admin' : nil,
|
||||||
services_enabled: e.try(:serviceEnabled),
|
services_enabled: e.try(:serviceEnabled),
|
||||||
|
member_status: e.try(:memberStatus),
|
||||||
email_maildrop: e.try(:mailRoutingAddress),
|
email_maildrop: e.try(:mailRoutingAddress),
|
||||||
email_password: e.try(:mailpassword),
|
email_password: e.try(:mailpassword),
|
||||||
nostr_key: e.try(:nostrKey) ? e.nostrKey.first : nil,
|
nostr_key: e.try(:nostrKey) ? e.nostrKey.first : nil,
|
||||||
@ -79,10 +78,20 @@ class LdapService < ApplicationService
|
|||||||
end
|
end
|
||||||
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
|
def fetch_organizations
|
||||||
attributes = %w{dn ou description}
|
attributes = %w{dn ou description}
|
||||||
filter = Net::LDAP::Filter.eq("objectClass", "organizationalUnit")
|
filter = Net::LDAP::Filter.eq("objectClass", "organizationalUnit")
|
||||||
# filter = Net::LDAP::Filter.eq("objectClass", "*")
|
|
||||||
treebase = "cn=users,#{ldap_suffix}"
|
treebase = "cn=users,#{ldap_suffix}"
|
||||||
|
|
||||||
entries = client.search(base: treebase, filter: filter, attributes: attributes)
|
entries = client.search(base: treebase, filter: filter, attributes: attributes)
|
||||||
|
@ -13,6 +13,16 @@
|
|||||||
title: 'Pending',
|
title: 'Pending',
|
||||||
value: @stats[:users_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 %>
|
<% end %>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@ -29,8 +39,12 @@
|
|||||||
<% @users.each do |user| %>
|
<% @users.each do |user| %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%= link_to(user.cn, admin_user_path(user.cn), class: 'ks-text-link') %></td>
|
<td><%= link_to(user.cn, admin_user_path(user.cn), class: 'ks-text-link') %></td>
|
||||||
<td><%= user.confirmed_at.nil? ? badge("pending", :yellow) : "" %></td>
|
<td>
|
||||||
<td><%= user.is_admin? ? badge("admin", :red) : "" %></td>
|
<%= user.confirmed_at.nil? ? badge("pending", :yellow) : "" %>
|
||||||
|
<%= @contributors.include?(user.cn) ? badge("contributor", :green) : "" %>
|
||||||
|
<%= @sustainers.include?(user.cn) ? badge("sustainer", :green) : "" %>
|
||||||
|
</td>
|
||||||
|
<td><%= @admins.include?(user.cn) ? badge("admin", :red) : "" %></td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -32,6 +32,13 @@
|
|||||||
<th>Roles</th>
|
<th>Roles</th>
|
||||||
<td><%= @user.is_admin? ? badge("admin", :red) : "—" %></td>
|
<td><%= @user.is_admin? ? badge("admin", :red) : "—" %></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Status</th>
|
||||||
|
<td>
|
||||||
|
<%= @user.is_contributing_member? ? badge("contributor", :green) : "" %>
|
||||||
|
<%= @user.is_paying_member? ? badge("sustainer", :green) : "" %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Invited by</th>
|
<th>Invited by</th>
|
||||||
<td>
|
<td>
|
||||||
|
@ -21,7 +21,7 @@ namespace :ldap do
|
|||||||
|
|
||||||
desc "Add custom attributes to schema"
|
desc "Add custom attributes to schema"
|
||||||
task add_custom_attributes: :environment do |t, args|
|
task add_custom_attributes: :environment do |t, args|
|
||||||
%w[ admin service_enabled nostr_key pgp_key ].each do |name|
|
%w[ admin service_enabled member_status nostr_key pgp_key ].each do |name|
|
||||||
Rake::Task["ldap:modify_ldap_schema"].invoke(name, "add")
|
Rake::Task["ldap:modify_ldap_schema"].invoke(name, "add")
|
||||||
Rake::Task['ldap:modify_ldap_schema'].reenable
|
Rake::Task['ldap:modify_ldap_schema'].reenable
|
||||||
end
|
end
|
||||||
@ -29,7 +29,7 @@ namespace :ldap do
|
|||||||
|
|
||||||
desc "Delete custom attributes from schema"
|
desc "Delete custom attributes from schema"
|
||||||
task delete_custom_attributes: :environment do |t, args|
|
task delete_custom_attributes: :environment do |t, args|
|
||||||
%w[ admin service_enabled nostr_key pgp_key ].each do |name|
|
%w[ admin service_enabled member_status nostr_key pgp_key ].each do |name|
|
||||||
Rake::Task["ldap:modify_ldap_schema"].invoke(name, "delete")
|
Rake::Task["ldap:modify_ldap_schema"].invoke(name, "delete")
|
||||||
Rake::Task['ldap:modify_ldap_schema'].reenable
|
Rake::Task['ldap:modify_ldap_schema'].reenable
|
||||||
end
|
end
|
||||||
|
8
schemas/ldap/member_status.ldif
Normal file
8
schemas/ldap/member_status.ldif
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
dn: cn=schema
|
||||||
|
changetype: modify
|
||||||
|
add: attributeTypes
|
||||||
|
attributeTypes: ( 1.3.6.1.4.1.61554.1.1.2.1.3
|
||||||
|
NAME 'memberStatus'
|
||||||
|
DESC 'Current member/contributor status'
|
||||||
|
EQUALITY caseExactMatch
|
||||||
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
@ -154,7 +154,7 @@ RSpec.describe User, type: :model do
|
|||||||
|
|
||||||
it "removes all services from the LDAP entry" do
|
it "removes all services from the LDAP entry" do
|
||||||
expect_any_instance_of(LdapService).to receive(:delete_attribute)
|
expect_any_instance_of(LdapService).to receive(:delete_attribute)
|
||||||
.with(dn, :service).and_return(true)
|
.with(dn, :serviceEnabled).and_return(true)
|
||||||
|
|
||||||
user.disable_all_services
|
user.disable_all_services
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user