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