org.go

  1package database
  2
  3import (
  4	"context"
  5
  6	"github.com/charmbracelet/soft-serve/pkg/access"
  7	"github.com/charmbracelet/soft-serve/pkg/db"
  8	"github.com/charmbracelet/soft-serve/pkg/db/models"
  9	"github.com/charmbracelet/soft-serve/pkg/store"
 10	"github.com/charmbracelet/soft-serve/pkg/utils"
 11)
 12
 13var _ store.OrgStore = (*orgStore)(nil)
 14
 15type orgStore struct{ *handleStore }
 16
 17// UpdateOrgContactEmail implements store.OrgStore.
 18func (*orgStore) UpdateOrgContactEmail(ctx context.Context, h db.Handler, org int64, email string) error {
 19	if err := utils.ValidateEmail(email); err != nil {
 20		return err
 21	}
 22
 23	query := h.Rebind(`
 24		UPDATE organizations
 25		SET
 26		  contact_email = ?
 27		WHERE
 28		  id = ?
 29	`)
 30
 31	_, err := h.ExecContext(ctx, query, email, org)
 32	return err
 33}
 34
 35// ListOrgs implements store.OrgStore.
 36func (*orgStore) ListOrgs(ctx context.Context, h db.Handler, uid int64) ([]models.Organization, error) {
 37	var m []models.Organization
 38	query := h.Rebind(`
 39		SELECT
 40		  o.*,
 41		  h AS handle
 42		FROM
 43		  organizations o
 44		  JOIN handles h ON h.id = o.handle_id
 45		  JOIN organization_members om ON om.org_id = o.id
 46		WHERE
 47		  o.user_id = ?
 48	`)
 49	err := h.SelectContext(ctx, &m, query, uid)
 50	return m, err
 51}
 52
 53// Delete implements store.OrgStore.
 54func (s *orgStore) DeleteOrgByID(ctx context.Context, h db.Handler, user, id int64) error {
 55	_, err := s.getOrgByIDWithAccess(ctx, h, user, id, access.AdminAccess)
 56	if err != nil {
 57		return err
 58	}
 59	query := h.Rebind(`DELETE FROM organizations WHERE id = ?;`)
 60	_, err = h.ExecContext(ctx, query, id)
 61	return err
 62}
 63
 64// Create implements store.OrgStore.
 65func (s *orgStore) CreateOrg(ctx context.Context, h db.Handler, user int64, name, email string) (models.Organization, error) {
 66	if err := utils.ValidateEmail(email); err != nil {
 67		return models.Organization{}, err
 68	}
 69
 70	handle, err := s.CreateHandle(ctx, h, name)
 71	if err != nil {
 72		return models.Organization{}, err
 73	}
 74
 75	query := h.Rebind(`
 76		INSERT INTO
 77		  organizations (handle_id, contact_email, updated_at)
 78		VALUES
 79		  (?, ?, CURRENT_TIMESTAMP) RETURNING id;
 80	`)
 81
 82	var id int64
 83	if err := h.GetContext(ctx, &id, query, handle, email); err != nil {
 84		return models.Organization{}, err
 85	}
 86	if err := s.AddUserToOrg(ctx, h, id, user, access.AdminAccess); err != nil {
 87		return models.Organization{}, err
 88	}
 89
 90	return s.GetOrgByID(ctx, h, user, id)
 91}
 92
 93func (*orgStore) UpdateUserAccessInOrg(ctx context.Context, h db.Handler, org, user int64, lvl access.AccessLevel) error {
 94	query := h.Rebind(`
 95		UPDATE organization_members
 96		WHERE
 97		  organization_id = ?
 98		  AND user_id = ?
 99		SET
100		  access_level = ?
101	`)
102	_, err := h.ExecContext(ctx, query, org, user, lvl)
103	return err
104}
105
106func (*orgStore) RemoveUserFromOrg(ctx context.Context, h db.Handler, org, user int64) error {
107	query := h.Rebind(`
108		DELETE FROM organization_members
109		WHERE
110		  organization_id = ?
111		  AND user_id = ?
112	`)
113	_, err := h.ExecContext(ctx, query, org, user)
114	return err
115}
116
117func (*orgStore) AddUserToOrg(ctx context.Context, h db.Handler, org, user int64, lvl access.AccessLevel) error {
118	query := h.Rebind(`
119		INSERT INTO
120		  organization_members (
121		    organization_id,
122		    user_id,
123		    access_level,
124		    updated_at
125		  )
126		VALUES
127		  (?, ?, ?, CURRENT_TIMESTAMP);
128	`)
129	_, err := h.ExecContext(ctx, query, org, user, lvl)
130	return err
131}
132
133// FindByName implements store.OrgStore.
134func (*orgStore) FindOrgByHandle(ctx context.Context, h db.Handler, user int64, name string) (models.Organization, error) {
135	var m models.Organization
136	query := h.Rebind(`
137		SELECT
138		  o.*,
139		  h AS handle
140		FROM
141		  organizations o
142		  JOIN handles h ON h.id = o.handle_id
143		  JOIN organization_members om ON om.organization_id = o.id
144		WHERE
145		  om.user_id = ?
146		  AND h.handle = ?;
147	`)
148	err := h.GetContext(ctx, &m, query, user, name)
149	return m, err
150}
151
152// GetByID implements store.OrgStore.
153func (s *orgStore) GetOrgByID(ctx context.Context, h db.Handler, user, id int64) (models.Organization, error) {
154	return s.getOrgByIDWithAccess(ctx, h, user, id, access.ReadOnlyAccess)
155}
156
157func (*orgStore) getOrgByIDWithAccess(ctx context.Context, h db.Handler, user, id int64, level access.AccessLevel) (models.Organization, error) {
158	var m models.Organization
159	query := h.Rebind(`
160		SELECT
161		  o.*,
162		  h AS handle
163		FROM
164		  organizations o
165		  JOIN handles h ON h.id = o.handle_id
166		  JOIN organization_members om ON om.organization_id = o.id
167		WHERE
168		  om.user_id = ?
169		  AND id = ?
170		  AND om.access_level >= ?;
171	`)
172	err := h.GetContext(ctx, &m, query, user, id, level)
173	return m, err
174}