Standardizing the API endpoints.

This commit is contained in:
Ada Werefox 2025-04-24 15:08:09 -07:00
parent 326fbe79a3
commit 10db069eea
3 changed files with 166 additions and 66 deletions

View file

@ -14,10 +14,15 @@ func main() {
api.GlobalConfig = configserver.ParseConfig("../config.toml")
api.GlobalOAuth = authdiscord.CreateDiscordOAuthConfig(api.GlobalConfig)
app := gin.Default()
app.GET("/login", api.LoginRedirect)
// Authentication Workflow
app.GET("/auth/callback", api.AuthCallback)
app.GET("/logout", api.LogoutRedirect)
app.GET("/dashboard", api.GetDashboardInfo)
app.GET("/authorized", api.IsUserAuthorized)
app.GET("/auth/login", api.AuthLoginRedirect)
app.GET("/auth/logout", api.AuthLogoutRedirect)
// Create & Update
app.POST("/post/user/update", api.CreateOrUpdateUser)
// Read
app.GET("/get/user/info", api.GetUserInfo)
app.GET("/get/user/authorized", api.GetIsUserAuthorized)
// Delete
app.Run(":31337")
}

View file

@ -21,20 +21,7 @@ var GlobalDatabase *gorm.DB
var GlobalConfig configserver.AppConfig
var GlobalOAuth *oauth2.Config
func LoginRedirect(context *gin.Context) {
context.Redirect(302, GlobalOAuth.AuthCodeURL(context.GetString("state")))
}
func LogoutRedirect(context *gin.Context) {
oauthTokenJSON, err := context.Cookie("discord-oauthtoken")
if err == nil {
databasecommands.LogoutDatabaseUser(GlobalDatabase, oauthTokenJSON)
context.SetCookie("discord-oauthtoken", "", -1, "", GlobalConfig.API.Domain, false, true)
} else {
log.Println(err)
}
context.Redirect(http.StatusTemporaryRedirect, "http://localhost:15995/")
}
// Authentication Workflow
func AuthCallback(context *gin.Context) {
oauthState := randomstring.CookieFriendlyString(32)
@ -46,12 +33,73 @@ func AuthCallback(context *gin.Context) {
}
oauthTokenJSON, _ := json.Marshal(oauthToken)
context.SetCookie("discord-oauthtoken", string(oauthTokenJSON), 0, "", GlobalConfig.API.Domain, false, false)
user := GetDiscordUser(context, oauthToken)
CreateOrUpdateUser(context, oauthToken, user)
context.Set("discord-oauthtoken", string(oauthTokenJSON))
CreateOrUpdateUser(context)
context.Redirect(http.StatusTemporaryRedirect, "http://localhost:15995/dashboard")
}
func GetDiscordUser(context *gin.Context, oauthToken *oauth2.Token) authdiscord.DiscordUser {
func AuthLoginRedirect(context *gin.Context) {
context.Redirect(302, GlobalOAuth.AuthCodeURL(context.GetString("state")))
}
func AuthLogoutRedirect(context *gin.Context) {
oauthTokenJSON, err := context.Cookie("discord-oauthtoken")
if err == nil {
databasecommands.LogoutDatabaseUser(GlobalDatabase, oauthTokenJSON)
context.SetCookie("discord-oauthtoken", "", -1, "", GlobalConfig.API.Domain, false, true)
} else {
log.Println(err)
}
context.Redirect(http.StatusTemporaryRedirect, "http://localhost:15995/")
}
// Create & Update Endpoints (post/, put/, patch)
func CreateOrUpdateUser(context *gin.Context) {
oauthTokenJSON, err := context.Cookie("discord-oauthtoken")
if err != nil {
oauthTokenJSON = context.GetString("discord-oauthtoken")
}
var oauthToken *oauth2.Token
err = json.Unmarshal([]byte(oauthTokenJSON), &oauthToken)
if err != nil {
log.Println(err)
context.AbortWithStatus(http.StatusBadRequest)
}
currentDiscordUser := getDiscordUser(context, oauthToken)
updatedDatabaseUser := databasemodels.User{
DisplayName: currentDiscordUser.Global_Name,
Username: currentDiscordUser.Username,
Id: currentDiscordUser.Id,
Avatar: currentDiscordUser.Avatar,
AvatarDecoration: currentDiscordUser.Avatar_Decoration_Data.Asset,
LoginToken: string(oauthTokenJSON),
LoggedIn: true,
}
if databasecommands.DatabaseUserExists(GlobalDatabase, currentDiscordUser.Id) {
dbOAuthToken := databasecommands.GetDatabaseUserToken(GlobalDatabase, currentDiscordUser.Id)
if dbOAuthToken == "" {
context.SetCookie("discord-oauthtoken", string(oauthTokenJSON), 0, "", GlobalConfig.API.Domain, false, false)
err := databasecommands.UpdateDatabaseUser(GlobalDatabase, updatedDatabaseUser)
if err != nil {
log.Println(err)
context.AbortWithStatus(http.StatusInternalServerError)
}
} else {
context.SetCookie("discord-oauthtoken", dbOAuthToken, 0, "", GlobalConfig.API.Domain, false, false)
}
} else {
err := databasecommands.CreateDatabaseUser(GlobalDatabase, updatedDatabaseUser)
if err != nil {
log.Println(err)
context.Copy().AbortWithStatus(http.StatusInternalServerError)
}
}
}
// Read Endpoints (get/)
func getDiscordUser(context *gin.Context, oauthToken *oauth2.Token) authdiscord.DiscordUser {
response, err := GlobalOAuth.Client(context.Request.Context(), oauthToken).Get("https://discord.com/api/users/@me")
if err != nil || response.StatusCode != 200 {
responseMessage := ""
@ -76,72 +124,43 @@ func GetDiscordUser(context *gin.Context, oauthToken *oauth2.Token) authdiscord.
return user
}
func CreateOrUpdateUser(context *gin.Context, oauthToken *oauth2.Token, user authdiscord.DiscordUser) {
oauthTokenJSON, err := json.Marshal(oauthToken)
if err != nil {
log.Println(err)
}
dbUser := databasemodels.User{
DisplayName: user.Global_Name,
Username: user.Username,
Id: user.Id,
Avatar: user.Avatar,
AvatarDecoration: user.Avatar_Decoration_Data.Asset,
LoginToken: string(oauthTokenJSON),
LoggedIn: true,
}
if databasecommands.DatabaseUserExists(GlobalDatabase, user.Id) {
dbOAuthToken := databasecommands.GetDatabaseUserToken(GlobalDatabase, user.Id)
if dbOAuthToken == "" {
context.SetCookie("discord-oauthtoken", string(oauthTokenJSON), 0, "", GlobalConfig.API.Domain, false, false)
err := databasecommands.UpdateDatabaseUser(GlobalDatabase, dbUser)
if err != nil {
log.Println(err)
}
} else {
context.SetCookie("discord-oauthtoken", dbOAuthToken, 0, "", GlobalConfig.API.Domain, false, false)
}
} else {
err := databasecommands.CreateDatabaseUser(GlobalDatabase, dbUser)
if err != nil {
log.Println(err)
}
}
}
func GetDashboardInfo(context *gin.Context) {
func GetUserInfo(context *gin.Context) {
oauthTokenJSON, err := context.Cookie("discord-oauthtoken")
if err == nil {
var oauthToken *oauth2.Token
err := json.Unmarshal([]byte(oauthTokenJSON), &oauthToken)
if err == nil {
if oauthToken.Valid() {
user := GetDiscordUser(context, oauthToken)
user := getDiscordUser(context, oauthToken)
if databasecommands.DatabaseUserLoggedIn(GlobalDatabase, user.Id) {
context.JSON(http.StatusOK, user)
return
} else {
context.Redirect(http.StatusTemporaryRedirect, "http://localhost:31337/logout")
context.Redirect(http.StatusTemporaryRedirect, "http://localhost:31337/auth/logout")
}
return
} else {
log.Println(err)
context.AbortWithStatus(http.StatusBadRequest)
}
} else {
log.Println(err)
context.AbortWithStatus(http.StatusBadRequest)
}
} else {
log.Println(err)
context.AbortWithStatus(http.StatusBadRequest)
}
context.Redirect(http.StatusTemporaryRedirect, "http://localhost:15995/")
}
func IsUserAuthorized(context *gin.Context) {
func GetIsUserAuthorized(context *gin.Context) {
oauthTokenJSON, err := context.Cookie("discord-oauthtoken")
if err == nil {
var oauthToken *oauth2.Token
err := json.Unmarshal([]byte(oauthTokenJSON), &oauthToken)
if err == nil {
if oauthToken.Valid() {
user := GetDiscordUser(context, oauthToken)
user := getDiscordUser(context, oauthToken)
if databasecommands.DatabaseUserLoggedIn(GlobalDatabase, user.Id) {
context.JSON(http.StatusOK, gin.H{
"message": true,
@ -152,16 +171,12 @@ func IsUserAuthorized(context *gin.Context) {
})
}
return
} else {
log.Println(err)
}
} else {
log.Println(err)
}
} else {
log.Println(err)
}
context.JSON(http.StatusUnauthorized, gin.H{
"message": false,
})
}
// Delete Endpoints (delete/)

View file

@ -12,3 +12,83 @@ type User struct {
LoginToken string
LoggedIn bool
}
type Person struct {
Name string
Groups []Group // Unique
}
type Group struct {
Name string
}
type Character struct {
Name string
Owners []Person // Unique
Roles []Role // Unique
FunctionSets []FunctionSet
Inventory []InventorySlot
}
type Role struct {
Name string
Tiers []Tier
Visibility []Group // Unique
}
type Tier struct {
FunctionSets []FunctionSet
}
type FunctionSet struct {
Functions []Function
}
type Function struct {
Name string
Tags FunctionTag
Requirements []Function
}
type FunctionTag struct {
Name string
}
type InventorySlot struct {
Item Item
Quantity int64 // Positive
}
type Item struct {
Name string
Functions []Function
FlavorText string
RulesDescription string
PhysrepRequirements string
Tags []ItemTag // Unique
Customizations []Customization
Visibility []Group // Unique
}
type ItemTag struct {
Naem string
}
type Customization struct {
Name string
Functions []Function
FlavorText string
RulesDescription string
PhysrepRequirements string
Tags []ItemTag // Unique
Visibility []Group // Unique
}
type Schematic struct {
Material []InventorySlot
Tools []InventorySlot
Requirements []Function
TimeUnits int64 // Positive
Result InventorySlot
Visibility []Group // Unique
}