From 6d4d2a10ad0d4f2ebc5a97a517de0b1a7891c783 Mon Sep 17 00:00:00 2001 From: Opaque02 <66582645+Opaque02@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:54:45 +1000 Subject: [PATCH] Changes to allow linking and unlinking of google Id from DB --- .vs/slnx.sqlite | Bin 90112 -> 90112 bytes api/common.go | 2 + api/endpoints.go | 121 ++++++++++++++++++++++++++++++++++++++++++++--- db/account.go | 32 +++++++++++-- 4 files changed, 146 insertions(+), 9 deletions(-) diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite index edded18c74ed110e988fc1d1967253d9bf199153..8441856d600fcc199c3246eb4e447aaf18d962dc 100644 GIT binary patch delta 1469 zcmZWpO-~a+7@loqx@}6gg?4w@LMq}18ZDI%t6b0s8d0jzc=Lm$oh~cgoo2U%kZ8ag zN6jW4y!i_Z>4}pZF(&>1&+|Ud`@HYY?D}@s`gYf=yp(v| ze_cv!&Oa$gqrr!Q+Iz7yLY~pm==kx{<;l{O$+5A{ULlc|%AMaMnRK+AFoW1tCz3Eb zne@+izfp!@NRpw4tv2$Jw~Ra}f8BeZ+WIvWyqGOKV6VmmEsI0nTt+psWfm=*;AQGK z1bM<)rh~$`HU_}}!E2`7SPc`w{;ayjeASDGv~lj4EkU4B?E(=BR2w<$D2Toy1cRj9 ztX6T`ZG|=Z1qcd+YBx!4n$I}sF+k?i&ojzj^;^gh6rKFt?cBeF#yK{*i&m-)WP0H; z{VX%6p#}IRI%e=H>}aluo?a{8#)ca1PSVy?vm|Ve(>XQa!Th5F;1}0e2^(m6mc?(GEuRoE5z?T9EDoR`@_i7TB5Ol#t%+^7 z<*$WhS)HCEnVmtQ(X}Jl1f!~SWSJi%fonOI%UY~@#Z{-#%X8(j5cHAuRhz?W2X{yB zr7dK*g1x1B1F!f|t}uGo_%|L_rf*elQkmei3{inNygzeodTyrZ)VL^@CbnZXj+moP^*SVS>t2L*`(x zUm1SJ&Q4DPf*c@QM0KCj={N)#iY;(NmC25X%K{?*2jnhuJQIVUmsFZfTR@OO#bx0a zyu7RZyK?$57PM&DE!%RjCxYgpbPY13%wk(~?uoE`6y`1R5(H;Rnquu>+`~Qz06;mp z3zU83yYfZ(q--ghsgK=(c5g0{-0jrvttHb+bVv&Q70aDJkCbS%oZ1Ou^JgQeola@~ rO$v5JB?*>0pWRDRw4B@sV$H{qb!YFt#((bXpn`Npa^= zGKmXT`V+{kOiU#1jD{azT#%R;U9m7MNqp1Cdl@k4>YRJdJ@?Li-9PTyKkj;yaCr`T z=Utwo&1Xs1g!w7SMl<))Qp|1Vb(_G{haLBsRp9toxWBr{?14iv&9jK>~5Is7g+pn}VPZ;U!V2 z?m7wcY?*CeYA3E}y~Hz?fq=8MTS!PzE`8OJ5V%=HBk7I+9RFxdww)Gfhin^-m znp4A#;u-!k8@dI-3<_EowThz2hWTg1f1f7{5k_zf!Xit`@x#}eQO4X~VJmpk{2(r> z>ayOnH^dTaZU84jjABQn1lx~4j-r)yC(b9am8|P>)m|x8n66c_H@@#$C|V@+;!%p* zq9#kVmeYVs;4DT%Y#4~}(2#;nF!TT^k?4V71g%ZdN;O^48b;eGi}CgyG57|lhUczj zqYTU1BQxZXD9*)kE_u6HPwlGJD9II%LC}NR7Zn1xJCA~o+ASE^((9FSRc{$?q7Wi@ z{D)8S3rqP$TShr9j8wo2ALr&4R&yz}L`3lr%7uuPrTJXGkRxy`h`J+K)>B4P#pvus zA{L;qs#6cX8$A+Kyr35=QoXEHC1Nw?hhPpdX8yUr5YRl!kG;UR6Y)V12WX2@*&uYt z3qjb%wg|#9Xh+CpOG5t-lD0$eum^%DsuXJqg&>AfI~~8m>$Q*Ot2OTO$?-RF(3Gq+ z6j{^jG-%vyuYrL!v)!bfBR6n98zwChE(k_ZnpCMX?o}Tj03ho>2f?%8ui*FK*WicX zQQ%9r$*r$i<@L7z;9bNze;RbVvw;)SvpH@}ZoUm1tTWb$mUX$a{zKDK+px;DK~x#D J4qujk{sTwk&&>b; diff --git a/api/common.go b/api/common.go index 1f287cd..bd4cf8a 100644 --- a/api/common.go +++ b/api/common.go @@ -70,6 +70,8 @@ func Init(mux *http.ServeMux) error { // admin mux.HandleFunc("POST /admin/account/discord-link", handleAdminDiscordLink) mux.HandleFunc("POST /admin/account/discord-unlink", handleAdminDiscordUnlink) + mux.HandleFunc("POST /admin/account/google-link", handleAdminGoogleLink) + mux.HandleFunc("POST /admin/account/google-unlink", handleAdminGoogleUnlink) mux.HandleFunc("GET /admin/account/admin-search", handleAdminSearch) return nil diff --git a/api/endpoints.go b/api/endpoints.go index 84e34d9..a1232c8 100644 --- a/api/endpoints.go +++ b/api/endpoints.go @@ -697,10 +697,10 @@ func handleAdminDiscordLink(w http.ResponseWriter, r *http.Request) { discordId := r.Form.Get("discordId") // this does a quick call to make sure the username exists on the server before allowing the rest of the code to run - // this calls error value 204 (StatusNoContent) if there's no data; this means the username does not exist in the server + // this calls error value 404 (StatusNotFound) if there's no data; this means the username does not exist in the server _, err = db.CheckUsernameExists(username) if err != nil { - httpError(w, r, fmt.Errorf("username does not exist on the server"), http.StatusNoContent) + httpError(w, r, fmt.Errorf("username does not exist on the server"), http.StatusNotFound) return } @@ -751,10 +751,10 @@ func handleAdminDiscordUnlink(w http.ResponseWriter, r *http.Request) { if username != "" { log.Printf("Username given, removing discordId") // this does a quick call to make sure the username exists on the server before allowing the rest of the code to run - // this calls error value 204 (StatusNoContent) if there's no data; this means the username does not exist in the server + // this calls error value 404 (StatusNotFound) if there's no data; this means the username does not exist in the server _, err = db.CheckUsernameExists(username) if err != nil { - httpError(w, r, fmt.Errorf("username does not exist on the server"), http.StatusNoContent) + httpError(w, r, fmt.Errorf("username does not exist on the server"), http.StatusNotFound) return } err = db.RemoveDiscordIdByUsername(username) @@ -777,6 +777,115 @@ func handleAdminDiscordUnlink(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } +func handleAdminGoogleLink(w http.ResponseWriter, r *http.Request) { + err := r.ParseForm() + if err != nil { + httpError(w, r, fmt.Errorf("failed to parse request form: %s", err), http.StatusBadRequest) + return + } + + uuid, err := uuidFromRequest(r) + if err != nil { + httpError(w, r, err, http.StatusUnauthorized) + return + } + + userDiscordId, err := db.FetchDiscordIdByUUID(uuid) + if err != nil { + httpError(w, r, err, http.StatusUnauthorized) + return + } + + hasRole, err := account.IsUserDiscordAdmin(userDiscordId, account.DiscordGuildID) + if !hasRole || err != nil { + httpError(w, r, fmt.Errorf("user does not have the required role"), http.StatusForbidden) + return + } + + username := r.Form.Get("username") + googleId := r.Form.Get("googleId") + + // this does a quick call to make sure the username exists on the server before allowing the rest of the code to run + // this calls error value 404 (StatusNotFound) if there's no data; this means the username does not exist in the server + _, err = db.CheckUsernameExists(username) + if err != nil { + httpError(w, r, fmt.Errorf("username does not exist on the server"), http.StatusNotFound) + return + } + + err = db.AddGoogleIdByUsername(googleId, username) + if err != nil { + httpError(w, r, err, http.StatusInternalServerError) + return + } + + log.Printf("%s: %s added google id %s to username %s", r.URL.Path, userDiscordId, googleId, username) + + w.WriteHeader(http.StatusOK) +} + +func handleAdminGoogleUnlink(w http.ResponseWriter, r *http.Request) { + err := r.ParseForm() + if err != nil { + httpError(w, r, fmt.Errorf("failed to parse request form: %s", err), http.StatusBadRequest) + return + } + + uuid, err := uuidFromRequest(r) + if err != nil { + httpError(w, r, err, http.StatusUnauthorized) + return + } + + userDiscordId, err := db.FetchDiscordIdByUUID(uuid) + if err != nil { + httpError(w, r, err, http.StatusUnauthorized) + return + } + + hasRole, err := account.IsUserDiscordAdmin(userDiscordId, account.DiscordGuildID) + if !hasRole || err != nil { + httpError(w, r, fmt.Errorf("user does not have the required role"), http.StatusForbidden) + return + } + + if err != nil { + httpError(w, r, err, http.StatusUnauthorized) + return + } + + username := r.Form.Get("username") + googleId := r.Form.Get("googleId") + + if username != "" { + log.Printf("Username given, removing googleId") + // this does a quick call to make sure the username exists on the server before allowing the rest of the code to run + // this calls error value 404 (StatusNotFound) if there's no data; this means the username does not exist in the server + _, err = db.CheckUsernameExists(username) + if err != nil { + httpError(w, r, fmt.Errorf("username does not exist on the server"), http.StatusNotFound) + return + } + err = db.RemoveGoogleIdByUsername(username) + if err != nil { + httpError(w, r, err, http.StatusInternalServerError) + return + } + } + if googleId != "" { + log.Printf("DiscordID given, removing googleId") + err = db.RemoveGoogleIdByDiscordId(googleId) + if err != nil { + httpError(w, r, err, http.StatusInternalServerError) + return + } + } + + log.Printf("%s: %s removed google id %s from username %s", userDiscordId, r.URL.Path, r.Form.Get("googleId"), r.Form.Get("username")) + + w.WriteHeader(http.StatusOK) +} + func handleAdminSearch(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { @@ -810,10 +919,10 @@ func handleAdminSearch(w http.ResponseWriter, r *http.Request) { username := r.Form.Get("username") // this does a quick call to make sure the username exists on the server before allowing the rest of the code to run - // this calls error value 204 (StatusNoContent) if there's no data; this means the username does not exist in the server + // this calls error value 404 (StatusNotFound) if there's no data; this means the username does not exist in the server _, err = db.CheckUsernameExists(username) if err != nil { - httpError(w, r, fmt.Errorf("username does not exist on the server"), http.StatusNoContent) + httpError(w, r, fmt.Errorf("username does not exist on the server"), http.StatusNotFound) return } diff --git a/db/account.go b/db/account.go index cfd9c4e..7bacf35 100644 --- a/db/account.go +++ b/db/account.go @@ -183,14 +183,15 @@ type AdminSearchResponse struct { DiscordId string `json:"discordId"` GoogleId string `json:"googleId"` LastLoggedIn string `json:"lastLoggedIn"` + Registered string `json:"registered"` } func FetchAdminDetailsByUsername(dbUsername string) (AdminSearchResponse, error) { - var resultUsername, resultDiscordId, resultGoogleId, resultLastLoggedIn sql.NullString - var username, discordId, googleId, lastLoggedIn string + var resultUsername, resultDiscordId, resultGoogleId, resultLastLoggedIn, resultRegistered sql.NullString + var username, discordId, googleId, lastLoggedIn, registered string var adminResponse AdminSearchResponse - err := handle.QueryRow("SELECT username, discordId, googleId, lastLoggedIn from accounts WHERE username = ?", dbUsername).Scan(&resultUsername, &resultDiscordId, &resultGoogleId, &resultLastLoggedIn) + err := handle.QueryRow("SELECT username, discordId, googleId, lastLoggedIn, registered from accounts WHERE username = ?", dbUsername).Scan(&resultUsername, &resultDiscordId, &resultGoogleId, &resultLastLoggedIn, &resultRegistered) if err != nil { return adminResponse, err } @@ -219,11 +220,18 @@ func FetchAdminDetailsByUsername(dbUsername string) (AdminSearchResponse, error) lastLoggedIn = "" } + if resultRegistered.Valid { + registered = resultRegistered.String + } else { + registered = "" + } + adminResponse = AdminSearchResponse{ Username: username, DiscordId: discordId, GoogleId: googleId, LastLoggedIn: lastLoggedIn, + Registered: registered, } return adminResponse, nil @@ -436,6 +444,15 @@ func RemoveGoogleIdByUUID(uuid []byte) error { return nil } +func RemoveGoogleIdByUsername(username string) error { + _, err := handle.Exec("UPDATE accounts SET googleId = NULL WHERE username = ?", username) + if err != nil { + return err + } + + return nil +} + func RemoveDiscordIdByUsername(username string) error { _, err := handle.Exec("UPDATE accounts SET discordId = NULL WHERE username = ?", username) if err != nil { @@ -451,5 +468,14 @@ func RemoveDiscordIdByDiscordId(discordId string) error { return err } + return nil +} + +func RemoveGoogleIdByDiscordId(discordId string) error { + _, err := handle.Exec("UPDATE accounts SET googleId = NULL WHERE discordId = ?", discordId) + if err != nil { + return err + } + return nil } \ No newline at end of file