1package queries
2
3import (
4 "database/sql"
5 "fmt"
6
7 "github.com/bnema/gordon/internal/db"
8 "github.com/bnema/gordon/internal/server"
9 "github.com/google/uuid"
10)
11
12func generateUUID() string {
13 return uuid.New().String()
14}
15
16// UserInfo holds the essential information for a Github user.
17type GithubUserInfo struct {
18 Login string `json:"login"`
19 AvatarURL string `json:"avatar_url"`
20 ProfileURL string `json:"html_url"`
21 Emails []string
22}
23
24// CreateUser creates a new user along with the associated account, provider, and session.
25func CreateUser(a *server.App, accessToken string, browserInfo string, userInfo *GithubUserInfo) error {
26 // Check if a user already exists. If so, return an error.
27 if exists, err := CheckDBUserExists(a); err != nil || exists {
28 return fmt.Errorf("error checking user or user already exists: %v", err)
29 }
30
31 user, err := createDBUser(a, userInfo)
32 if err != nil {
33 return err
34 }
35
36 // update the global state
37 a.DBTables.User.ID = user.ID
38 a.DBTables.User.Name = user.Name
39 a.DBTables.User.Email = user.Email
40
41 account, err := createDBAccount(a)
42 if err != nil {
43 return err
44 }
45
46 // update the global state
47 a.DBTables.Account.ID = account.ID
48 a.DBTables.Account.UserID = account.UserID
49
50 err = createDBGitHubProvider(a, userInfo)
51 if err != nil {
52 return err
53 }
54
55 return createDBSession(a, browserInfo, accessToken, account.ID)
56}
57
58func createDBUser(a *server.App, userInfo *GithubUserInfo) (*db.User, error) {
59 user := &db.User{
60 ID: generateUUID(),
61 Name: userInfo.Login,
62 Email: userInfo.Emails[0],
63 }
64
65 _, err := a.DB.Exec(
66 "INSERT INTO user (id, name, email) VALUES (?, ?, ?)",
67 user.ID, user.Name, user.Email,
68 )
69 return user, err
70}
71
72func CheckDBUserExists(a *server.App) (bool, error) {
73 var userID string
74 err := a.DB.QueryRow("SELECT id FROM user").Scan(&userID)
75 if err != nil {
76 if err == sql.ErrNoRows {
77 return false, nil
78 }
79 return false, err
80 }
81
82 if userID != "" {
83 return true, nil
84 }
85
86 return false, nil
87}
88
89// If there is already a user, we compare the login and email to see if it is the same user
90func CheckDBUserIsGood(a *server.App, userInfo *GithubUserInfo) (bool, error) {
91 login := userInfo.Login
92 email := userInfo.Emails[0]
93
94 // Check if the user exists based on github login and email
95 query := "SELECT user.id, user.name, user.email FROM user INNER JOIN account ON user.id = account.user_id INNER JOIN provider ON account.id = provider.account_id WHERE provider.login = ? AND provider.email = ?"
96 err := a.DB.QueryRow(query, login, email).Scan(&a.DBTables.User.ID, &a.DBTables.User.Name, &a.DBTables.User.Email)
97 if err != nil {
98 if err == sql.ErrNoRows {
99 return false, nil
100 }
101 return false, err
102 }
103
104 if a.DBTables.User.ID != "" {
105 return true, nil
106 }
107
108 return false, nil
109}
110
111func UpdateUser(a *server.App, accessToken string, browserInfo string, userInfo *GithubUserInfo) (*db.User, error) {
112
113 err := CreateOrUpdateDBSession(a, accessToken, browserInfo)
114 if err != nil {
115 return nil, fmt.Errorf("could not create or update session: %w", err)
116 }
117
118 user := a.DBTables.User
119
120 query := "SELECT user.id, user.name, user.email FROM user INNER JOIN account ON user.id = account.user_id INNER JOIN provider ON account.id = provider.account_id WHERE provider.login = ? AND provider.email = ?"
121 err = a.DB.QueryRow(query, userInfo.Login, userInfo.Emails[0]).Scan(&user.ID, &user.Name, &user.Email)
122 if err != nil {
123 return nil, err
124 }
125
126 return &user, nil
127
128}
129
130func GetAccountCount(a *server.App) (int, error) {
131 var count int
132 err := a.DB.QueryRow("SELECT COUNT(*) FROM account").Scan(&count)
133 if err != nil {
134 return 0, err
135 }
136
137 return count, nil
138}