10 Commits

Author SHA1 Message Date
Râu Cao
6d20ac9a1c Add lndhub info to admin user page
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-02-25 15:33:03 +08:00
Râu Cao
27dd4163f0 Add more data to admin user page 2023-02-25 15:32:50 +08:00
Râu Cao
1a55e5e895 Link users everywhere in admin panel 2023-02-25 15:32:13 +08:00
Râu Cao
8eb487600c Switch admin users index from pure LDAP to database 2023-02-25 15:31:19 +08:00
Râu Cao
678e80a25d Retrieve ldap entry from user model 2023-02-25 15:30:23 +08:00
Râu Cao
30fb9805e5 Add associations between users via invitations 2023-02-25 15:29:46 +08:00
Râu Cao
e675970f4c Add view helper for colored badges 2023-02-25 15:28:02 +08:00
Râu Cao
a0727e709f Add table class for rows with dividers 2023-02-25 15:27:28 +08:00
Râu Cao
55abbcc5ad WIP user page 2023-02-23 23:55:32 +08:00
Râu Cao
ffed398024 Add admin user details page 2023-02-23 22:09:23 +08:00
15 changed files with 207 additions and 55 deletions

View File

@@ -7,16 +7,30 @@
@apply text-left;
}
table th {
table thead th {
@apply pb-3.5 text-sm font-normal uppercase text-gray-500;
}
table tbody th {
@apply text-left font-normal text-gray-500;
}
table th:not(:last-of-type),
table td:not(:last-of-type) {
@apply pr-2;
}
table td {
table td, tbody th {
@apply py-2;
}
table.divided {
@apply divide-y divide-gray-300;
}
table.divided tbody {
@apply divide-y divide-gray-200;
}
table.divided td, table.divided tbody th {
@apply py-3;
}
}

View File

@@ -1,19 +1,32 @@
class Admin::UsersController < Admin::BaseController
before_action :set_user, only: [:show]
before_action :set_current_section
def index
ldap = LdapService.new
@ou = params[:ou] || "kosmos.org"
@orgs = ldap.fetch_organizations
@entries = ldap.fetch_users(ou: @ou)
ldap = LdapService.new
@ou = params[:ou] || "kosmos.org"
@orgs = ldap.fetch_organizations
@users = User.where(ou: @ou).order(cn: :asc).to_a
@stats = {
users_confirmed: User.where(ou: @ou).confirmed.count,
users_pending: User.where(ou: @ou).pending.count
}
end
def show
if Setting.lndhub_admin_enabled?
@lndhub_user = @user.lndhub_user
end
end
private
def set_user
address = params[:address].split("@")
@user = User.where(cn: address.first, ou: address.last).first
end
def set_current_section
@current_section = :users
end

View File

@@ -10,5 +10,12 @@ module ApplicationHelper
"text-gray-300 hover:bg-gray-900/30 hover:text-white active:bg-gray-900/30 active:text-white px-3 py-2 rounded-md font-medium text-base md:text-sm block md:inline-block"
end
end
# Colors available: gray, red, yellow, green, blue, purple, pink
# (Add more colors by adding classes to the safelist in tailwind.config.js)
def badge(text, color)
tag.span text, class: "inline-flex items-center rounded-full bg-#{color}-100 px-2.5 py-0.5 text-xs font-medium text-#{color}-800"
end
end

View File

@@ -1,6 +1,7 @@
class Invitation < ApplicationRecord
# Relations
belongs_to :user
belongs_to :invitee, class_name: "User", foreign_key: 'invited_user_id', optional: true
# Validations
validates_presence_of :user

View File

@@ -10,6 +10,18 @@ class LndhubUser < LndhubBase
foreign_key: "login"
def balance
accounts.current.first.ledgers.sum("account_ledgers.amount")
accounts.current.first.ledgers.sum("account_ledgers.amount").to_i.abs
end
def sum_outgoing
accounts.outgoing.first.ledgers.sum("account_ledgers.amount").to_i.abs
end
def sum_incoming
accounts.incoming.first.ledgers.sum("account_ledgers.amount").to_i.abs
end
def sum_fees
accounts.fees.first.ledgers.sum("account_ledgers.amount").to_i.abs
end
end

View File

@@ -3,6 +3,10 @@ class User < ApplicationRecord
# Relations
has_many :invitations, dependent: :destroy
has_one :invitation, inverse_of: :invitee, foreign_key: 'invited_user_id'
has_one :inviter, through: :invitation, source: :user
has_many :invitees, through: :invitations
has_many :donations, dependent: :nullify
has_one :lndhub_user, class_name: "LndhubUser", inverse_of: "user",
@@ -66,6 +70,12 @@ class User < ApplicationRecord
end
end
def ldap_entry
return @ldap_entry if defined?(@ldap_entry)
ldap = LdapService.new
@ldap_entry = ldap.fetch_users(uid: self.cn, ou: self.ou).first
end
def address
"#{self.cn}@#{self.ou}"
end

View File

@@ -43,7 +43,7 @@ class LdapService < ApplicationService
end
attributes = %w{dn cn uid mail admin}
filter = Net::LDAP::Filter.eq("uid", "*")
filter = Net::LDAP::Filter.eq("uid", args[:uid] || "*")
entries = ldap_client.search(base: treebase, filter: filter, attributes: attributes)
entries.sort_by! { |e| e.cn[0] }

View File

@@ -21,7 +21,7 @@
<section>
<% if @donations.any? %>
<h3>Recent Donations</h3>
<table>
<table class="divided">
<thead>
<tr>
<th>User</th>
@@ -33,11 +33,10 @@
<th></th>
</tr>
</thead>
<tbody>
<% @donations.each do |donation| %>
<tr>
<td><%= donation.user.address %></td>
<td><%= link_to donation.user.address, admin_user_path(donation.user.address), class: 'ks-text-link' %></td>
<td class="text-right"><%= sats_to_btc donation.amount_sats %></td>
<td class="text-right"><% if donation.amount_eur.present? %><%= number_to_currency donation.amount_eur / 100, unit: "" %><% end %></td>
<td class="text-right"><% if donation.amount_usd.present? %><%= number_to_currency donation.amount_usd / 100, unit: "" %><% end %></td>

View File

@@ -1,35 +1,34 @@
<%= render HeaderComponent.new(title: "Donations") %>
<%= render MainSimpleComponent.new do %>
<p>
<strong>User:</strong>
<%= @donation.user.address %>
</p>
<p>
<strong>Amount sats:</strong>
<%= @donation.amount_sats %>
</p>
<p>
<strong>Amount eur:</strong>
<%= @donation.amount_eur %>
</p>
<p>
<strong>Amount usd:</strong>
<%= @donation.amount_usd %>
</p>
<p>
<strong>Public name:</strong>
<%= @donation.public_name %>
</p>
<p>
<strong>Date:</strong>
<%= @donation.paid_at %>
</p>
<table class="w-1/2">
<tbody>
<tr>
<th>User</th>
<td><%= link_to @donation.user.address, admin_user_path(@donation.user.address), class: 'ks-text-link' %></td>
</tr>
<tr>
<th>Amount sats</th>
<td><%= @donation.amount_sats %></td>
</tr>
<tr>
<th>Amount EUR</th>
<td><%= @donation.amount_eur %></td>
</tr>
<tr>
<th>Amount USD</th>
<td><%= @donation.amount_usd %></td>
</tr>
<tr>
<th>Public name</th>
<td><%= @donation.public_name %></td>
</tr>
<tr>
<th>Date</th>
<td><%= @donation.paid_at.strftime("%Y-%m-%d (%H:%M UTC)") %></td>
</tr>
</tbody>
</table>
<p class="mt-8">
<%= link_to 'Edit', edit_admin_donation_path(@donation), class: 'ks-text-link' %> |

View File

@@ -24,7 +24,7 @@
<% if @invitations_used.any? %>
<section>
<h3>Recently Accepted</h3>
<table>
<table class="divided">
<thead>
<tr>
<th>Token</th>
@@ -38,8 +38,8 @@
<tr>
<td class="overflow-ellipsis font-mono"><%= invitation.token %></td>
<td><%= invitation.used_at.strftime("%Y-%m-%d (%H:%M UTC)") %></td>
<td><%= invitation.user.address %></td>
<td><%= User.find(invitation.invited_user_id).address %></td>
<td><%= link_to invitation.user.address, admin_user_path(invitation.user.address), class: "ks-text-link" %></td>
<td><%= link_to invitation.invitee.address, admin_user_path(invitation.invitee.address), class: "ks-text-link" %></td>
</tr>
<% end %>
</tbody>

View File

@@ -20,7 +20,7 @@
<section>
<h3>Accounts</h3>
<table>
<table class="divided">
<thead>
<tr>
<th>LN Account</th>
@@ -36,7 +36,7 @@
</td>
<td>
<% if user = @users.find{ |u| u[2] == account.login } %>
<%= "#{user[0]}@#{user[1]}" %>
<%= link_to "#{user[0]}@#{user[1]}", admin_user_path("#{user[0]}@#{user[1]}"), class: "ks-text-link" %>
<% end %>
</td>
<td><%= number_with_delimiter account.balance.to_i.to_s %></td>

View File

@@ -30,22 +30,21 @@
<% end %>
<section>
<table>
<table class="divided">
<thead>
<tr>
<th>UID</th>
<th>E-Mail</th>
<th>Admin</th>
<th>Status</th>
<th>Roles</th>
<!-- <th>Password</th> -->
</tr>
</thead>
<tbody>
<% @entries.each do |entry| %>
<% @users.each do |user| %>
<tr>
<td><%= entry[:uid] %></td>
<td><%= entry[:mail] %></td>
<td><%= entry[:admin] %></td>
<!-- <td><%= entry[:password] %></td> -->
<td><%= link_to(user.cn, admin_user_path(user.address), class: 'ks-text-link') %></td>
<td><%= user.confirmed_at.nil? ? badge("pending", :yellow) : "" %></td>
<td><%= user.is_admin? ? badge("admin", :red) : "" %></td>
</tr>
<% end %>
</tbody>

View File

@@ -0,0 +1,89 @@
<%= render HeaderComponent.new(title: "User: #{@user.address}") %>
<%= render MainSimpleComponent.new do %>
<section>
<h3>Account</h3>
<table class="w-1/2 divided">
<tbody>
<tr>
<th>Created at</th>
<td><%= @user.created_at.strftime("%Y-%m-%d (%H:%M UTC)") %></td>
</tr>
<tr>
<th>Confirmed at</th>
<td>
<% if @user.confirmed_at %>
<%= @user.confirmed_at.strftime("%Y-%m-%d (%H:%M UTC)") %>
<% else %>
<%= badge "pending", :yellow %>
<% end %>
</td>
</tr>
<tr>
<th>Email</th>
<td><%= @user.email %></td>
</tr>
<tr>
<th>Roles</th>
<td><%= @user.is_admin? ? badge("admin", :red) : "—" %></td>
</tr>
<tr>
<th>Invited by</th>
<td>
<% if @user.inviter %>
<%= link_to @user.inviter.address, admin_user_path(@user.inviter.address), class: 'ks-text-link' %>
<% else %>&mdash;<% end %>
</td>
</tr>
<tr>
<th>Invitations available</th>
<td>
<%= @user.invitations.count %>
</td>
</tr>
<tr>
<th class="align-top">Invited users</th>
<td class="align-top">
<% if @user.invitees.length > 0 %>
<ul class="mb-0">
<% @user.invitees.order(cn: :asc).each do |invitee| %>
<li class="leading-none mb-2 last:mb-0"><%= link_to invitee.address, admin_user_path(invitee.address), class: 'ks-text-link' %></li>
<% end %>
</ul>
<% else %>&mdash;<% end %>
</td>
</tr>
</tbody>
</table>
</section>
<% if Setting.lndhub_admin_enabled? %>
<section>
<h3>LndHub</h3>
<% if @lndhub_user %>
<table>
<thead>
<tr>
<th>Account</th>
<th>Balance</th>
<th>Incoming</th>
<th>Outgoing</th>
<th>Fees</th>
</tr>
</thead>
<tbody>
<tr>
<td><%= @user.ln_account %></td>
<td><%= number_with_delimiter @lndhub_user.balance %> sats</td>
<td><%= number_with_delimiter @lndhub_user.sum_incoming %> sats</td>
<td><%= number_with_delimiter @lndhub_user.sum_outgoing %> sats</td>
<td><%= number_with_delimiter @lndhub_user.sum_fees %> sats</td>
</tr>
</tbody>
</table>
<% else %>
<p>No LndHub user found for account <strong class="font-mono"><%= @user.ln_account %></strong>.
<% end %>
</section>
<% end %>
<% end %>

View File

@@ -39,7 +39,7 @@ Rails.application.routes.draw do
namespace :admin do
root to: 'dashboard#index'
resources 'users', only: ['index']
resources 'users', param: 'address', only: ['index', 'show'], constraints: { address: /.*/ }
get 'invitations', to: 'invitations#index'
resources :donations
get 'lightning', to: 'lightning#index'

View File

@@ -7,6 +7,15 @@ module.exports = {
'./app/helpers/**/*.rb',
'./app/javascript/**/*.js'
],
safelist: [
'bg-gray-100', 'text-gray-800',
'bg-red-100', 'text-red-800',
'bg-yellow-100', 'text-yellow-800',
'bg-green-100', 'text-green-800',
'bg-blue-100', 'text-blue-800',
'bg-purple-100', 'text-purple-800',
'bg-pink-100', 'text-pink-800',
],
theme: {
extend: {
fontFamily: {
@@ -16,5 +25,5 @@ module.exports = {
},
plugins: [
require('@tailwindcss/forms')
],
]
}