172 lines
3.9 KiB
Go
172 lines
3.9 KiB
Go
package sshkey
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
)
|
|
|
|
type SQLRepository struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
func NewSQLRepository(db *sql.DB) SQLRepository {
|
|
return SQLRepository{db: db}
|
|
}
|
|
|
|
func (r SQLRepository) List(ctx context.Context, profileID string, tenantID string) ([]SSHKey, bool, error) {
|
|
rows, err := r.db.QueryContext(ctx, `
|
|
select
|
|
sk.id::text,
|
|
sk.tenant_id::text,
|
|
sk.name,
|
|
sk.public_key,
|
|
sk.created_at
|
|
from public.tenants t
|
|
join public.memberships m
|
|
on m.tenant_id = t.id
|
|
and m.profile_id = $1
|
|
join public.ssh_keys sk
|
|
on sk.tenant_id = t.id
|
|
where t.id = $2
|
|
order by sk.created_at desc, sk.name asc
|
|
`, profileID, tenantID)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var keys []SSHKey
|
|
for rows.Next() {
|
|
var k SSHKey
|
|
if err := rows.Scan(&k.ID, &k.TenantID, &k.Name, &k.PublicKey, &k.CreatedAt); err != nil {
|
|
return nil, false, err
|
|
}
|
|
keys = append(keys, k)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
if len(keys) == 0 {
|
|
exists, err := r.tenantExists(ctx, profileID, tenantID)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
return keys, exists, nil
|
|
}
|
|
|
|
return keys, true, nil
|
|
}
|
|
|
|
func (r SQLRepository) Get(ctx context.Context, profileID string, keyID string) (SSHKey, bool, error) {
|
|
var k SSHKey
|
|
err := r.db.QueryRowContext(ctx, `
|
|
select
|
|
sk.id::text,
|
|
sk.tenant_id::text,
|
|
sk.name,
|
|
sk.public_key,
|
|
sk.created_at
|
|
from public.ssh_keys sk
|
|
join public.memberships m
|
|
on m.tenant_id = sk.tenant_id
|
|
and m.profile_id = $1
|
|
where sk.id = $2
|
|
`, profileID, keyID).Scan(&k.ID, &k.TenantID, &k.Name, &k.PublicKey, &k.CreatedAt)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return SSHKey{}, false, nil
|
|
}
|
|
if err != nil {
|
|
return SSHKey{}, false, err
|
|
}
|
|
|
|
return k, true, nil
|
|
}
|
|
|
|
func (r SQLRepository) Create(ctx context.Context, profileID string, tenantID string, name string, publicKey string) (SSHKey, bool, error) {
|
|
exists, err := r.tenantMemberExists(ctx, profileID, tenantID)
|
|
if err != nil {
|
|
return SSHKey{}, false, err
|
|
}
|
|
if !exists {
|
|
return SSHKey{}, false, nil
|
|
}
|
|
|
|
var k SSHKey
|
|
err = r.db.QueryRowContext(ctx, `
|
|
insert into public.ssh_keys (tenant_id, name, public_key)
|
|
values ($1, $2, $3)
|
|
returning id::text, tenant_id::text, name, public_key, created_at
|
|
`, tenantID, name, publicKey).Scan(&k.ID, &k.TenantID, &k.Name, &k.PublicKey, &k.CreatedAt)
|
|
if err != nil {
|
|
return SSHKey{}, false, err
|
|
}
|
|
|
|
return k, true, nil
|
|
}
|
|
|
|
func (r SQLRepository) Delete(ctx context.Context, profileID string, keyID string) (bool, bool, error) {
|
|
var tenantID string
|
|
err := r.db.QueryRowContext(ctx, `
|
|
select sk.tenant_id::text
|
|
from public.ssh_keys sk
|
|
where sk.id = $1
|
|
`, keyID).Scan(&tenantID)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return false, false, nil
|
|
}
|
|
if err != nil {
|
|
return false, false, err
|
|
}
|
|
|
|
member, err := r.tenantMemberExists(ctx, profileID, tenantID)
|
|
if err != nil {
|
|
return false, false, err
|
|
}
|
|
if !member {
|
|
return false, true, nil
|
|
}
|
|
|
|
res, err := r.db.ExecContext(ctx, `
|
|
delete from public.ssh_keys
|
|
where id = $1
|
|
`, keyID)
|
|
if err != nil {
|
|
return false, false, err
|
|
}
|
|
rowsAffected, err := res.RowsAffected()
|
|
if err != nil {
|
|
return false, false, err
|
|
}
|
|
|
|
return rowsAffected > 0, true, nil
|
|
}
|
|
|
|
func (r SQLRepository) tenantExists(ctx context.Context, profileID string, tenantID string) (bool, error) {
|
|
var exists bool
|
|
err := r.db.QueryRowContext(ctx, `
|
|
select exists(
|
|
select 1
|
|
from public.tenants t
|
|
join public.memberships m
|
|
on m.tenant_id = t.id
|
|
and m.profile_id = $1
|
|
where t.id = $2
|
|
)
|
|
`, profileID, tenantID).Scan(&exists)
|
|
return exists, err
|
|
}
|
|
|
|
func (r SQLRepository) tenantMemberExists(ctx context.Context, profileID string, tenantID string) (bool, error) {
|
|
var exists bool
|
|
err := r.db.QueryRowContext(ctx, `
|
|
select exists(
|
|
select 1
|
|
from public.memberships
|
|
where profile_id = $1
|
|
and tenant_id = $2
|
|
)
|
|
`, profileID, tenantID).Scan(&exists)
|
|
return exists, err
|
|
} |