mirror of https://github.com/agola-io/agola
1094 lines
30 KiB
Go
1094 lines
30 KiB
Go
package db
|
|
|
|
import (
|
|
"context"
|
|
stdsql "database/sql"
|
|
"path"
|
|
"strings"
|
|
|
|
sq "github.com/huandu/go-sqlbuilder"
|
|
"github.com/rs/zerolog"
|
|
"github.com/sorintlab/errors"
|
|
|
|
"agola.io/agola/internal/services/configstore/common"
|
|
"agola.io/agola/internal/services/configstore/db/objects"
|
|
"agola.io/agola/internal/sqlg"
|
|
"agola.io/agola/internal/sqlg/sql"
|
|
"agola.io/agola/services/configstore/types"
|
|
)
|
|
|
|
type DB struct {
|
|
log zerolog.Logger
|
|
sdb *sql.DB
|
|
}
|
|
|
|
func NewDB(log zerolog.Logger, sdb *sql.DB) (*DB, error) {
|
|
return &DB{
|
|
log: log,
|
|
sdb: sdb,
|
|
}, nil
|
|
}
|
|
|
|
func (d *DB) DBType() sql.Type {
|
|
return d.sdb.Type()
|
|
}
|
|
|
|
func (d *DB) DB() *sql.DB {
|
|
return d.sdb
|
|
}
|
|
|
|
func (d *DB) Do(ctx context.Context, f func(tx *sql.Tx) error) error {
|
|
return errors.WithStack(d.sdb.Do(ctx, f))
|
|
}
|
|
|
|
func (d *DB) ObjectsInfo() []sqlg.ObjectInfo {
|
|
return objects.ObjectsInfo
|
|
}
|
|
|
|
func (d *DB) Flavor() sq.Flavor {
|
|
switch d.sdb.Type() {
|
|
case sql.Postgres:
|
|
return sq.PostgreSQL
|
|
case sql.Sqlite3:
|
|
return sq.SQLite
|
|
}
|
|
|
|
return sq.PostgreSQL
|
|
}
|
|
|
|
func (d *DB) exec(tx *sql.Tx, rq sq.Builder) (stdsql.Result, error) {
|
|
q, args := rq.BuildWithFlavor(d.Flavor())
|
|
// d.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args))
|
|
|
|
r, err := tx.Exec(q, args...)
|
|
return r, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) query(tx *sql.Tx, rq sq.Builder) (*stdsql.Rows, error) {
|
|
q, args := rq.BuildWithFlavor(d.Flavor())
|
|
// d.log.Debug().Msgf("start q: %s, args: %s", q, util.Dump(args))
|
|
|
|
r, err := tx.Query(q, args...)
|
|
// d.log.Debug().Msgf("end q: %s, args: %s", q, util.Dump(args))
|
|
return r, errors.WithStack(err)
|
|
}
|
|
|
|
func mustSingleRow[T any](s []*T) (*T, error) {
|
|
if len(s) > 1 {
|
|
return nil, errors.Errorf("too many rows returned")
|
|
}
|
|
if len(s) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
return s[0], nil
|
|
}
|
|
|
|
func (d *DB) GetPath(tx *sql.Tx, objectKind types.ObjectKind, id string) (string, error) {
|
|
var p string
|
|
switch objectKind {
|
|
case types.ObjectKindProjectGroup:
|
|
projectGroup, err := d.GetProjectGroup(tx, id)
|
|
if err != nil {
|
|
return "", errors.WithStack(err)
|
|
}
|
|
if projectGroup == nil {
|
|
return "", errors.Errorf("projectgroup with id %q doesn't exist", id)
|
|
}
|
|
p, err = d.GetProjectGroupPath(tx, projectGroup)
|
|
if err != nil {
|
|
return "", errors.WithStack(err)
|
|
}
|
|
case types.ObjectKindProject:
|
|
project, err := d.GetProject(tx, id)
|
|
if err != nil {
|
|
return "", errors.WithStack(err)
|
|
}
|
|
if project == nil {
|
|
return "", errors.Errorf("project with id %q doesn't exist", id)
|
|
}
|
|
p, err = d.GetProjectPath(tx, project)
|
|
if err != nil {
|
|
return "", errors.WithStack(err)
|
|
}
|
|
case types.ObjectKindOrg:
|
|
org, err := d.GetOrg(tx, id)
|
|
if err != nil {
|
|
return "", errors.Wrapf(err, "failed to get org %q", id)
|
|
}
|
|
if org == nil {
|
|
return "", errors.Errorf("cannot find org with id %q", id)
|
|
}
|
|
p = path.Join("org", org.Name)
|
|
case types.ObjectKindUser:
|
|
user, err := d.GetUser(tx, id)
|
|
if err != nil {
|
|
return "", errors.Wrapf(err, "failed to get user %q", id)
|
|
}
|
|
if user == nil {
|
|
return "", errors.Errorf("cannot find user with id %q", id)
|
|
}
|
|
p = path.Join("user", user.Name)
|
|
default:
|
|
return "", errors.Errorf("config type %q doesn't provide a path", objectKind)
|
|
}
|
|
|
|
return p, nil
|
|
}
|
|
|
|
func (d *DB) GetRemoteSource(tx *sql.Tx, rsRef string) (*types.RemoteSource, error) {
|
|
refType, err := common.ParseNameRef(rsRef)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
var rs *types.RemoteSource
|
|
switch refType {
|
|
case common.RefTypeID:
|
|
rs, err = d.GetRemoteSourceByID(tx, rsRef)
|
|
case common.RefTypeName:
|
|
rs, err = d.GetRemoteSourceByName(tx, rsRef)
|
|
}
|
|
return rs, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetRemoteSourceByID(tx *sql.Tx, remoteSourceID string) (*types.RemoteSource, error) {
|
|
q := remoteSourceSelect()
|
|
q.Where(q.E("id", remoteSourceID))
|
|
remoteSources, _, err := d.fetchRemoteSources(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(remoteSources)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetRemoteSourceByName(tx *sql.Tx, name string) (*types.RemoteSource, error) {
|
|
q := remoteSourceSelect()
|
|
q.Where(q.E("name", name))
|
|
remoteSources, _, err := d.fetchRemoteSources(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(remoteSources)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func getRemoteSourcesFilteredQuery(startRemoteSourceName string, limit int, asc bool) *sq.SelectBuilder {
|
|
q := remoteSourceSelect()
|
|
if asc {
|
|
q = q.OrderBy("remotesource.name").Asc()
|
|
} else {
|
|
q = q.OrderBy("remotesource.name").Desc()
|
|
}
|
|
if startRemoteSourceName != "" {
|
|
if asc {
|
|
q = q.Where(q.G("remotesource.name", startRemoteSourceName))
|
|
} else {
|
|
q = q.Where(q.L("remotesource.name", startRemoteSourceName))
|
|
}
|
|
}
|
|
if limit > 0 {
|
|
q = q.Limit(limit)
|
|
}
|
|
|
|
return q
|
|
}
|
|
|
|
func (d *DB) GetRemoteSources(tx *sql.Tx, startRemoteSourceName string, limit int, asc bool) ([]*types.RemoteSource, error) {
|
|
q := getRemoteSourcesFilteredQuery(startRemoteSourceName, limit, asc)
|
|
remoteSources, _, err := d.fetchRemoteSources(tx, q)
|
|
|
|
return remoteSources, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetUser(tx *sql.Tx, userRef string) (*types.User, error) {
|
|
refType, err := common.ParseNameRef(userRef)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
var user *types.User
|
|
switch refType {
|
|
case common.RefTypeID:
|
|
user, err = d.GetUserByID(tx, userRef)
|
|
case common.RefTypeName:
|
|
user, err = d.GetUserByName(tx, userRef)
|
|
}
|
|
return user, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetUserByID(tx *sql.Tx, userID string) (*types.User, error) {
|
|
q := userSelect()
|
|
q.Where(q.E("id", userID))
|
|
users, _, err := d.fetchUsers(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(users)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetUserByName(tx *sql.Tx, name string) (*types.User, error) {
|
|
q := userSelect()
|
|
q.Where(q.E("name", name))
|
|
users, _, err := d.fetchUsers(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(users)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetUserTokens(tx *sql.Tx, userID string) ([]*types.UserToken, error) {
|
|
q := userTokenSelect()
|
|
q.Join("user_t", "usertoken.user_id = user_t.id").Where(q.E("user_t.id", userID))
|
|
tokens, _, err := d.fetchUserTokens(tx, q)
|
|
|
|
return tokens, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetUserToken(tx *sql.Tx, userID, tokenName string) (*types.UserToken, error) {
|
|
q := userTokenSelect()
|
|
q.Join("user_t", "usertoken.user_id = user_t.id")
|
|
q.Where(q.E("user_t.id", userID), q.E("usertoken.name", tokenName))
|
|
|
|
userTokens, _, err := d.fetchUserTokens(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(userTokens)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetUserByTokenValue(tx *sql.Tx, tokenValue string) (*types.User, error) {
|
|
q := userSelect()
|
|
q = q.Join("usertoken", "usertoken.user_id = user_t.id")
|
|
q = q.Where(q.E("usertoken.value", tokenValue))
|
|
|
|
users, _, err := d.fetchUsers(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(users)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetLinkedAccounts(tx *sql.Tx, linkedAccountsIDs []string) ([]*types.LinkedAccount, error) {
|
|
q := linkedAccountSelect()
|
|
q.Where(q.E("id", linkedAccountsIDs))
|
|
linkedAccounts, _, err := d.fetchLinkedAccounts(tx, q)
|
|
|
|
return linkedAccounts, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetLinkedAccount(tx *sql.Tx, linkedAccountID string) (*types.LinkedAccount, error) {
|
|
q := linkedAccountSelect()
|
|
q.Where(q.E("id", linkedAccountID))
|
|
linkedAccounts, _, err := d.fetchLinkedAccounts(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(linkedAccounts)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
// func (d *DB) GetLinkedAccount(tx *sql.Tx, userID, linkedAccountID string) (*types.LinkedAccount, error) {
|
|
// q := linkedAccountSelect()
|
|
// q..Eq{"id": linkedAccountID, "user_id": userID))
|
|
// linkedAccounts, _, err := d.fetchLinkedAccounts(tx, q)
|
|
// if err != nil {
|
|
// return nil, errors.WithStack(err)
|
|
// }
|
|
//
|
|
// out, err := mustSingleRow(linkedAccounts)
|
|
// return out, errors.WithStack(err)
|
|
// }
|
|
|
|
func (d *DB) GetUserLinkedAccounts(tx *sql.Tx, userID string) ([]*types.LinkedAccount, error) {
|
|
q := linkedAccountSelect()
|
|
q.Join("user_t", "linkedaccount.user_id = user_t.id").Where(q.E("user_t.id", userID))
|
|
|
|
linkedAccounts, _, err := d.fetchLinkedAccounts(tx, q)
|
|
|
|
return linkedAccounts, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetUserByLinkedAccount(tx *sql.Tx, linkedAccountID string) (*types.User, error) {
|
|
q := userSelect()
|
|
q = q.Join("linkedaccount", "linkedaccount.user_id = user_t.id")
|
|
q = q.Where(q.E("linkedaccount.id", linkedAccountID))
|
|
|
|
users, _, err := d.fetchUsers(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(users)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetLinkedAccountByRemoteUserIDandSource(tx *sql.Tx, remoteUserID, remoteSourceID string) (*types.LinkedAccount, error) {
|
|
q := linkedAccountSelect()
|
|
q.Where(q.E("linkedaccount.remote_user_id", remoteUserID), q.E("linkedaccount.remote_source_id", remoteSourceID))
|
|
|
|
linkedAccounts, _, err := d.fetchLinkedAccounts(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(linkedAccounts)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
// func (d *DB) GetUserByLinkedAccountRemoteUserIDandSource(tx *sql.Tx, remoteUserID, remoteSourceID string) (*types.User, error) {
|
|
// q := userSelect()
|
|
// q = q.Join("linkedaccount", "linkedaccount.user_id = user_t.id")
|
|
// q = q.Where(q.E("linkedaccount.remote_user_id", remoteUserID), q.E("linkedaccount.remote_source_id", remoteSourceID))
|
|
|
|
// users, _, err := d.fetchUsers(tx, q)
|
|
// if err != nil {
|
|
// return nil, errors.WithStack(err)
|
|
// }
|
|
|
|
// out, err := mustSingleRow(users)
|
|
// return out, errors.WithStack(err)
|
|
// }
|
|
|
|
func getUsersFilteredQuery(startUserName string, limit int, asc bool) *sq.SelectBuilder {
|
|
q := userSelect()
|
|
if asc {
|
|
q = q.OrderBy("user_t.name").Asc()
|
|
} else {
|
|
q = q.OrderBy("user_t.name").Desc()
|
|
}
|
|
if startUserName != "" {
|
|
if asc {
|
|
q = q.Where(q.G("user_t.name", startUserName))
|
|
} else {
|
|
q = q.Where(q.L("user_t.name", startUserName))
|
|
}
|
|
}
|
|
if limit > 0 {
|
|
q = q.Limit(limit)
|
|
}
|
|
|
|
return q
|
|
}
|
|
|
|
func (d *DB) GetUsers(tx *sql.Tx, startUserName string, limit int, asc bool) ([]*types.User, error) {
|
|
q := getUsersFilteredQuery(startUserName, limit, asc)
|
|
users, _, err := d.fetchUsers(tx, q)
|
|
|
|
return users, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetOrg(tx *sql.Tx, orgRef string) (*types.Organization, error) {
|
|
refType, err := common.ParseNameRef(orgRef)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
var org *types.Organization
|
|
switch refType {
|
|
case common.RefTypeID:
|
|
org, err = d.GetOrgByID(tx, orgRef)
|
|
case common.RefTypeName:
|
|
org, err = d.GetOrgByName(tx, orgRef)
|
|
}
|
|
return org, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetOrgByID(tx *sql.Tx, orgID string) (*types.Organization, error) {
|
|
q := organizationSelect()
|
|
q.Where(q.E("id", orgID))
|
|
orgs, _, err := d.fetchOrganizations(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(orgs)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetOrgByName(tx *sql.Tx, name string) (*types.Organization, error) {
|
|
q := organizationSelect()
|
|
q.Where(q.E("name", name))
|
|
orgs, _, err := d.fetchOrganizations(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(orgs)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func getOrgsFilteredQuery(startOrgName string, limit int, asc bool) *sq.SelectBuilder {
|
|
q := organizationSelect()
|
|
if asc {
|
|
q = q.OrderBy("name").Asc()
|
|
} else {
|
|
q = q.OrderBy("name").Desc()
|
|
}
|
|
if startOrgName != "" {
|
|
if asc {
|
|
q = q.Where(q.G("name", startOrgName))
|
|
} else {
|
|
q = q.Where(q.L("name", startOrgName))
|
|
}
|
|
}
|
|
if limit > 0 {
|
|
q = q.Limit(limit)
|
|
}
|
|
|
|
return q
|
|
}
|
|
|
|
func (d *DB) GetOrgs(tx *sql.Tx, startOrgName string, limit int, asc bool) ([]*types.Organization, error) {
|
|
q := getOrgsFilteredQuery(startOrgName, limit, asc)
|
|
orgs, _, err := d.fetchOrganizations(tx, q)
|
|
|
|
return orgs, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetOrgMemberByOrgUserID(tx *sql.Tx, orgID, userID string) (*types.OrganizationMember, error) {
|
|
q := organizationMemberSelect()
|
|
q.Where(q.E("orgmember.organization_id", orgID), q.E("orgmember.user_id", userID))
|
|
|
|
oms, _, err := d.fetchOrganizationMembers(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(oms)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
type OrgUser struct {
|
|
User *types.User
|
|
Role types.MemberRole
|
|
}
|
|
|
|
// TODO(sgotti) implement cursor fetching
|
|
func (d *DB) GetOrgUsers(tx *sql.Tx, orgID string) ([]*OrgUser, error) {
|
|
cols := organizationMemberSelectColumns()
|
|
cols = append(cols, userSelectColumns()...)
|
|
|
|
q := sq.Select(cols...).From("orgmember")
|
|
q = q.Join("user_t", "user_t.id = orgmember.user_id")
|
|
q = q.Where(q.E("orgmember.organization_id", orgID))
|
|
q = q.OrderBy("user_t.name")
|
|
|
|
rows, err := d.query(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
orgusers := []*OrgUser{}
|
|
for rows.Next() {
|
|
orgMemberCols := d.OrganizationMemberArray()
|
|
userCols := d.UserArray()
|
|
if err := d.scanArray(rows, orgMemberCols, userCols); err != nil {
|
|
return nil, errors.Wrapf(err, "failed to scan rows")
|
|
}
|
|
|
|
orgMember, _, err := d.OrganizationMemberFromArray(orgMemberCols, tx.ID())
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to fetch org")
|
|
}
|
|
|
|
user, _, err := d.UserFromArray(userCols, tx.ID())
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to fetch user")
|
|
}
|
|
|
|
orgusers = append(orgusers, &OrgUser{
|
|
User: user,
|
|
Role: orgMember.MemberRole,
|
|
})
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
return orgusers, nil
|
|
}
|
|
|
|
type UserOrg struct {
|
|
Organization *types.Organization
|
|
Role types.MemberRole
|
|
}
|
|
|
|
// TODO(sgotti) implement cursor fetching
|
|
func (d *DB) GetUserOrgs(tx *sql.Tx, userID string) ([]*UserOrg, error) {
|
|
cols := organizationMemberSelectColumns()
|
|
cols = append(cols, organizationSelectColumns()...)
|
|
|
|
q := sq.Select(cols...).From("orgmember")
|
|
q = q.Where(q.E("orgmember.user_id", userID))
|
|
q = q.Join("organization", "organization.id = orgmember.organization_id")
|
|
q = q.OrderBy("organization.name")
|
|
|
|
rows, err := d.query(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
userorgs := []*UserOrg{}
|
|
for rows.Next() {
|
|
orgMemberCols := d.OrganizationMemberArray()
|
|
organizationCols := d.OrganizationArray()
|
|
if err := d.scanArray(rows, orgMemberCols, organizationCols); err != nil {
|
|
return nil, errors.Wrapf(err, "failed to scan rows")
|
|
}
|
|
|
|
orgMember, _, err := d.OrganizationMemberFromArray(orgMemberCols, tx.ID())
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to fetch org")
|
|
}
|
|
|
|
org, _, err := d.OrganizationFromArray(organizationCols, tx.ID())
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to fetch org")
|
|
}
|
|
|
|
userorgs = append(userorgs, &UserOrg{
|
|
Organization: org,
|
|
Role: orgMember.MemberRole,
|
|
})
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
return userorgs, nil
|
|
}
|
|
|
|
type Element struct {
|
|
ID string
|
|
Name string
|
|
Kind types.ObjectKind
|
|
ParentKind types.ObjectKind
|
|
ParentID string
|
|
}
|
|
|
|
func (d *DB) GetProjectGroupHierarchy(tx *sql.Tx, projectGroup *types.ProjectGroup) ([]*Element, error) {
|
|
projectGroupID := projectGroup.Parent.ID
|
|
elements := []*Element{
|
|
{
|
|
ID: projectGroup.ID,
|
|
Name: projectGroup.Name,
|
|
Kind: types.ObjectKindProjectGroup,
|
|
ParentKind: projectGroup.Parent.Kind,
|
|
ParentID: projectGroup.Parent.ID,
|
|
},
|
|
}
|
|
|
|
for projectGroup.Parent.Kind == types.ObjectKindProjectGroup {
|
|
var err error
|
|
projectGroup, err = d.GetProjectGroup(tx, projectGroupID)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to get project group %q", projectGroupID)
|
|
}
|
|
if projectGroup == nil {
|
|
return nil, errors.Errorf("project group %q doesn't exist", projectGroupID)
|
|
}
|
|
elements = append([]*Element{
|
|
{
|
|
ID: projectGroup.ID,
|
|
Name: projectGroup.Name,
|
|
Kind: types.ObjectKindProjectGroup,
|
|
ParentKind: projectGroup.Parent.Kind,
|
|
ParentID: projectGroup.Parent.ID,
|
|
},
|
|
}, elements...)
|
|
projectGroupID = projectGroup.Parent.ID
|
|
}
|
|
|
|
return elements, nil
|
|
}
|
|
|
|
func (d *DB) GetProjectGroupPath(tx *sql.Tx, group *types.ProjectGroup) (string, error) {
|
|
var p string
|
|
|
|
groups, err := d.GetProjectGroupHierarchy(tx, group)
|
|
if err != nil {
|
|
return "", errors.WithStack(err)
|
|
}
|
|
|
|
rootGroupType := groups[0].ParentKind
|
|
rootGroupID := groups[0].ParentID
|
|
switch rootGroupType {
|
|
case types.ObjectKindOrg:
|
|
fallthrough
|
|
case types.ObjectKindUser:
|
|
var err error
|
|
p, err = d.GetPath(tx, rootGroupType, rootGroupID)
|
|
if err != nil {
|
|
return "", errors.WithStack(err)
|
|
}
|
|
default:
|
|
return "", errors.Errorf("invalid root group type %q", rootGroupType)
|
|
}
|
|
|
|
for _, group := range groups {
|
|
p = path.Join(p, group.Name)
|
|
}
|
|
|
|
return p, nil
|
|
}
|
|
|
|
func (d *DB) GetProjectGroupOwnerID(tx *sql.Tx, group *types.ProjectGroup) (types.ObjectKind, string, error) {
|
|
groups, err := d.GetProjectGroupHierarchy(tx, group)
|
|
if err != nil {
|
|
return "", "", errors.WithStack(err)
|
|
}
|
|
|
|
rootGroupType := groups[0].ParentKind
|
|
rootGroupID := groups[0].ParentID
|
|
return rootGroupType, rootGroupID, nil
|
|
}
|
|
|
|
func (d *DB) GetProjectGroup(tx *sql.Tx, projectGroupRef string) (*types.ProjectGroup, error) {
|
|
groupRef, err := common.ParsePathRef(projectGroupRef)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
var group *types.ProjectGroup
|
|
switch groupRef {
|
|
case common.RefTypeID:
|
|
group, err = d.GetProjectGroupByID(tx, projectGroupRef)
|
|
case common.RefTypePath:
|
|
group, err = d.GetProjectGroupByPath(tx, projectGroupRef)
|
|
}
|
|
return group, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetProjectGroupByID(tx *sql.Tx, projectGroupID string) (*types.ProjectGroup, error) {
|
|
q := projectGroupSelect()
|
|
q.Where(q.E("id", projectGroupID))
|
|
projectGroups, _, err := d.fetchProjectGroups(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(projectGroups)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetProjectGroupByName(tx *sql.Tx, parentID, name string) (*types.ProjectGroup, error) {
|
|
q := projectGroupSelect()
|
|
q.Where(q.E("parent_id", parentID), q.E("name", name))
|
|
projectGroups, _, err := d.fetchProjectGroups(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(projectGroups)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetProjectGroupByPath(tx *sql.Tx, projectGroupPath string) (*types.ProjectGroup, error) {
|
|
parts := strings.Split(projectGroupPath, "/")
|
|
if len(parts) < 2 {
|
|
return nil, errors.Errorf("wrong project group path: %q", projectGroupPath)
|
|
}
|
|
var parentID string
|
|
switch parts[0] {
|
|
case "org":
|
|
org, err := d.GetOrgByName(tx, parts[1])
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to get org %q", parts[1])
|
|
}
|
|
if org == nil {
|
|
return nil, errors.Errorf("cannot find org with name %q", parts[1])
|
|
}
|
|
parentID = org.ID
|
|
case "user":
|
|
user, err := d.GetUserByName(tx, parts[1])
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to get user %q", parts[1])
|
|
}
|
|
if user == nil {
|
|
return nil, errors.Errorf("cannot find user with name %q", parts[1])
|
|
}
|
|
parentID = user.ID
|
|
default:
|
|
return nil, errors.Errorf("wrong project group path: %q", projectGroupPath)
|
|
}
|
|
|
|
var projectGroup *types.ProjectGroup
|
|
// add root project group (empty name)
|
|
for _, projectGroupName := range append([]string{""}, parts[2:]...) {
|
|
var err error
|
|
projectGroup, err = d.GetProjectGroupByName(tx, parentID, projectGroupName)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to get project group %q", projectGroupName)
|
|
}
|
|
if projectGroup == nil {
|
|
return nil, nil
|
|
}
|
|
parentID = projectGroup.ID
|
|
}
|
|
|
|
return projectGroup, nil
|
|
}
|
|
|
|
func (d *DB) GetProjectGroupSubgroups(tx *sql.Tx, parentID string) ([]*types.ProjectGroup, error) {
|
|
q := projectGroupSelect()
|
|
q.Where(q.E("parent_id", parentID))
|
|
projectGroups, _, err := d.fetchProjectGroups(tx, q)
|
|
|
|
return projectGroups, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetProjectPath(tx *sql.Tx, project *types.Project) (string, error) {
|
|
pgroup, err := d.GetProjectGroup(tx, project.Parent.ID)
|
|
if err != nil {
|
|
return "", errors.WithStack(err)
|
|
}
|
|
if pgroup == nil {
|
|
return "", errors.Errorf("parent group %q for project %q doesn't exist", project.Parent.ID, project.ID)
|
|
}
|
|
p, err := d.GetProjectGroupPath(tx, pgroup)
|
|
if err != nil {
|
|
return "", errors.WithStack(err)
|
|
}
|
|
|
|
p = path.Join(p, project.Name)
|
|
|
|
return p, nil
|
|
}
|
|
|
|
func (d *DB) GetProjectOwnerID(tx *sql.Tx, project *types.Project) (types.ObjectKind, string, error) {
|
|
pgroup, err := d.GetProjectGroup(tx, project.Parent.ID)
|
|
if err != nil {
|
|
return "", "", errors.WithStack(err)
|
|
}
|
|
if pgroup == nil {
|
|
return "", "", errors.Errorf("parent group %q for project %q doesn't exist", project.Parent.ID, project.ID)
|
|
}
|
|
return d.GetProjectGroupOwnerID(tx, pgroup)
|
|
}
|
|
|
|
func (d *DB) GetProject(tx *sql.Tx, projectRef string) (*types.Project, error) {
|
|
projectRefType, err := common.ParsePathRef(projectRef)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
var project *types.Project
|
|
switch projectRefType {
|
|
case common.RefTypeID:
|
|
project, err = d.GetProjectByID(tx, projectRef)
|
|
case common.RefTypePath:
|
|
project, err = d.GetProjectByPath(tx, projectRef)
|
|
}
|
|
return project, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetProjectByID(tx *sql.Tx, projectID string) (*types.Project, error) {
|
|
q := projectSelect()
|
|
q.Where(q.E("id", projectID))
|
|
|
|
projects, _, err := d.fetchProjects(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(projects)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetProjectByName(tx *sql.Tx, parentID, name string) (*types.Project, error) {
|
|
q := projectSelect()
|
|
q.Where(q.E("parent_id", parentID), q.E("name", name))
|
|
|
|
projects, _, err := d.fetchProjects(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(projects)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetProjectByPath(tx *sql.Tx, projectPath string) (*types.Project, error) {
|
|
if len(strings.Split(projectPath, "/")) < 3 {
|
|
return nil, errors.Errorf("wrong project path: %q", projectPath)
|
|
}
|
|
|
|
projectGroupPath := path.Dir(projectPath)
|
|
projectName := path.Base(projectPath)
|
|
projectGroup, err := d.GetProjectGroupByPath(tx, projectGroupPath)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to get project group %q", projectGroupPath)
|
|
}
|
|
if projectGroup == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
project, err := d.GetProjectByName(tx, projectGroup.ID, projectName)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to get project group %q", projectName)
|
|
}
|
|
|
|
return project, nil
|
|
}
|
|
|
|
func (d *DB) GetProjectGroupProjects(tx *sql.Tx, parentID string) ([]*types.Project, error) {
|
|
q := projectSelect()
|
|
q.Where(q.E("parent_id", parentID))
|
|
projects, _, err := d.fetchProjects(tx, q)
|
|
|
|
return projects, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetSecretByID(tx *sql.Tx, secretID string) (*types.Secret, error) {
|
|
q := secretSelect()
|
|
q.Where(q.E("id", secretID))
|
|
secrets, _, err := d.fetchSecrets(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(secrets)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetSecretByName(tx *sql.Tx, parentID, name string) (*types.Secret, error) {
|
|
q := secretSelect()
|
|
q.Where(q.E("parent_id", parentID), q.E("name", name))
|
|
secrets, _, err := d.fetchSecrets(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(secrets)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetSecrets(tx *sql.Tx, parentID string) ([]*types.Secret, error) {
|
|
q := secretSelect()
|
|
q.Where(q.E("parent_id", parentID))
|
|
secrets, _, err := d.fetchSecrets(tx, q)
|
|
return secrets, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetSecretTree(tx *sql.Tx, parentKind types.ObjectKind, parentID, name string) (*types.Secret, error) {
|
|
for parentKind == types.ObjectKindProjectGroup || parentKind == types.ObjectKindProject {
|
|
secret, err := d.GetSecretByName(tx, parentID, name)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to get secret with name %q", name)
|
|
}
|
|
if secret != nil {
|
|
return secret, nil
|
|
}
|
|
|
|
switch parentKind {
|
|
case types.ObjectKindProjectGroup:
|
|
projectGroup, err := d.GetProjectGroup(tx, parentID)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
if projectGroup == nil {
|
|
return nil, errors.Errorf("projectgroup with id %q doesn't exist", parentID)
|
|
}
|
|
parentKind = projectGroup.Parent.Kind
|
|
parentID = projectGroup.Parent.ID
|
|
case types.ObjectKindProject:
|
|
project, err := d.GetProject(tx, parentID)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
if project == nil {
|
|
return nil, errors.Errorf("project with id %q doesn't exist", parentID)
|
|
}
|
|
parentKind = project.Parent.Kind
|
|
parentID = project.Parent.ID
|
|
}
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
func (d *DB) GetSecretsTree(tx *sql.Tx, parentKind types.ObjectKind, parentID string) ([]*types.Secret, error) {
|
|
allSecrets := []*types.Secret{}
|
|
|
|
for parentKind == types.ObjectKindProjectGroup || parentKind == types.ObjectKindProject {
|
|
secrets, err := d.GetSecrets(tx, parentID)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to get secrets for %s %q", parentKind, parentID)
|
|
}
|
|
allSecrets = append(allSecrets, secrets...)
|
|
|
|
switch parentKind {
|
|
case types.ObjectKindProjectGroup:
|
|
projectGroup, err := d.GetProjectGroup(tx, parentID)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
if projectGroup == nil {
|
|
return nil, errors.Errorf("projectgroup with id %q doesn't exist", parentID)
|
|
}
|
|
parentKind = projectGroup.Parent.Kind
|
|
parentID = projectGroup.Parent.ID
|
|
case types.ObjectKindProject:
|
|
project, err := d.GetProject(tx, parentID)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
if project == nil {
|
|
return nil, errors.Errorf("project with id %q doesn't exist", parentID)
|
|
}
|
|
parentKind = project.Parent.Kind
|
|
parentID = project.Parent.ID
|
|
}
|
|
}
|
|
|
|
return allSecrets, nil
|
|
}
|
|
|
|
func (d *DB) GetVariableByID(tx *sql.Tx, variableID string) (*types.Variable, error) {
|
|
q := variableSelect()
|
|
q.Where(q.E("id", variableID))
|
|
variables, _, err := d.fetchVariables(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(variables)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetVariableByName(tx *sql.Tx, parentID, name string) (*types.Variable, error) {
|
|
q := variableSelect()
|
|
q.Where(q.E("parent_id", parentID), q.E("name", name))
|
|
variables, _, err := d.fetchVariables(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(variables)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetVariables(tx *sql.Tx, parentID string) ([]*types.Variable, error) {
|
|
q := variableSelect()
|
|
q.Where(q.E("parent_id", parentID))
|
|
variables, _, err := d.fetchVariables(tx, q)
|
|
return variables, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetVariablesTree(tx *sql.Tx, parentKind types.ObjectKind, parentID string) ([]*types.Variable, error) {
|
|
allVariables := []*types.Variable{}
|
|
|
|
for parentKind == types.ObjectKindProjectGroup || parentKind == types.ObjectKindProject {
|
|
vars, err := d.GetVariables(tx, parentID)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to get variables for %s %q", parentKind, parentID)
|
|
}
|
|
allVariables = append(allVariables, vars...)
|
|
|
|
switch parentKind {
|
|
case types.ObjectKindProjectGroup:
|
|
projectGroup, err := d.GetProjectGroup(tx, parentID)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
if projectGroup == nil {
|
|
return nil, errors.Errorf("projectgroup with id %q doesn't exist", parentID)
|
|
}
|
|
parentKind = projectGroup.Parent.Kind
|
|
parentID = projectGroup.Parent.ID
|
|
case types.ObjectKindProject:
|
|
project, err := d.GetProject(tx, parentID)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
if project == nil {
|
|
return nil, errors.Errorf("project with id %q doesn't exist", parentID)
|
|
}
|
|
parentKind = project.Parent.Kind
|
|
parentID = project.Parent.ID
|
|
}
|
|
}
|
|
|
|
return allVariables, nil
|
|
}
|
|
|
|
// Test only functions
|
|
func (d *DB) GetAllProjects(tx *sql.Tx) ([]*types.Project, error) {
|
|
q := projectSelect()
|
|
q.OrderBy("id")
|
|
projects, _, err := d.fetchProjects(tx, q)
|
|
|
|
return projects, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetAllProjectGroups(tx *sql.Tx) ([]*types.ProjectGroup, error) {
|
|
q := projectGroupSelect()
|
|
q.OrderBy("id")
|
|
projectGroups, _, err := d.fetchProjectGroups(tx, q)
|
|
|
|
return projectGroups, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetAllSecrets(tx *sql.Tx) ([]*types.Secret, error) {
|
|
q := secretSelect()
|
|
q.OrderBy("id")
|
|
secrets, _, err := d.fetchSecrets(tx, q)
|
|
|
|
return secrets, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetAllVariables(tx *sql.Tx) ([]*types.Variable, error) {
|
|
q := variableSelect()
|
|
q.OrderBy("id")
|
|
variables, _, err := d.fetchVariables(tx, q)
|
|
|
|
return variables, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetOrgInvitations(tx *sql.Tx, orgID string) ([]*types.OrgInvitation, error) {
|
|
q := orgInvitationSelect()
|
|
q.Where(q.E("organization_id", orgID))
|
|
orgInvitations, _, err := d.fetchOrgInvitations(tx, q)
|
|
|
|
return orgInvitations, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetOrgInvitationByOrgUserID(tx *sql.Tx, orgID, userID string) (*types.OrgInvitation, error) {
|
|
q := orgInvitationSelect()
|
|
q.Where(q.E("organization_id", orgID), q.E("user_id", userID))
|
|
|
|
orgInvitations, _, err := d.fetchOrgInvitations(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
out, err := mustSingleRow(orgInvitations)
|
|
return out, errors.WithStack(err)
|
|
}
|
|
|
|
func (d *DB) GetOrgInvitationByUserID(tx *sql.Tx, userID string) ([]*types.OrgInvitation, error) {
|
|
q := orgInvitationSelect()
|
|
q.Where(q.E("user_id", userID))
|
|
|
|
orgInvitations, _, err := d.fetchOrgInvitations(tx, q)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
return orgInvitations, errors.WithStack(err)
|
|
}
|