diff --git a/app/database/database.go b/app/database/database.go
new file mode 100644
index 0000000..636bab8
--- /dev/null
+++ b/app/database/database.go
@@ -0,0 +1 @@
+package database
diff --git a/app/http/endpoints/callback.go b/app/http/endpoints/callback.go
new file mode 100644
index 0000000..aa74c44
--- /dev/null
+++ b/app/http/endpoints/callback.go
@@ -0,0 +1,67 @@
+package endpoints
+
+import (
+ "github.com/TicketsBot/GoPanel/utils/discord"
+ "github.com/TicketsBot/GoPanel/utils/discord/endpoints/user"
+ "github.com/TicketsBot/GoPanel/utils/discord/objects"
+ "github.com/gin-gonic/contrib/sessions"
+ "github.com/gin-gonic/gin"
+ "time"
+)
+
+type(
+ TokenData struct {
+ ClientId string `qs:"client_id"`
+ ClientSecret string `qs:"client_secret"`
+ GrantType string `qs:"grant_type"`
+ Code string `qs:"code"`
+ RedirectUri string `qs:"redirect_uri"`
+ Scope string `qs:"scope"`
+ }
+
+ TokenResponse struct {
+ AccessToken string `json:"access_token"`
+ TokenType string `json:"token_type"`
+ ExpiresIn int `json:"expires_in"`
+ RefreshToken string `json:"refresh_token"`
+ Scope string `json:"scope"`
+ }
+)
+
+func CallbackHandler(ctx *gin.Context) {
+ store := sessions.Default(ctx)
+ if store == nil {
+ return
+ }
+ defer store.Save()
+
+ code := ctx.DefaultQuery("code", "")
+ if code == "" {
+ ctx.String(400, "Discord provided an invalid Oauth2 code")
+ return
+ }
+
+ res, err := discord.AccessToken(code); if err != nil {
+ ctx.String(500, err.Error())
+ }
+
+ store.Set("access_token", res.AccessToken)
+ store.Set("refresh_token", res.RefreshToken)
+ store.Set("expiry", (time.Now().UnixNano() / int64(time.Second)) + int64(res.ExpiresIn))
+
+ // Get ID + name
+ var currentUser objects.User
+ err = user.CurrentUser.Request(store, nil, nil, ¤tUser); if err != nil {
+ ctx.String(500, err.Error())
+ return
+ }
+
+ store.Set("userid", currentUser.Id)
+ store.Set("name", currentUser.Username)
+
+ // Get Guilds
+ var currentUserGuilds []objects.Guild
+ err = user.CurrentUserGuilds.Request(store, nil, nil, ¤tUserGuilds); if err != nil {
+ ctx.String(500, err.Error())
+ }
+}
diff --git a/app/http/endpoints/index.go b/app/http/endpoints/index.go
new file mode 100644
index 0000000..3899d21
--- /dev/null
+++ b/app/http/endpoints/index.go
@@ -0,0 +1,22 @@
+package endpoints
+
+import (
+ "github.com/TicketsBot/GoPanel/utils"
+ "github.com/gin-gonic/contrib/sessions"
+ "github.com/gin-gonic/gin"
+)
+
+func IndexHandler(ctx *gin.Context) {
+ store := sessions.Default(ctx)
+ if store == nil {
+ return
+ }
+ defer store.Save()
+
+ if utils.IsLoggedIn(store) {
+
+ } else {
+ ctx.Redirect(302, "/login")
+ }
+}
+
diff --git a/app/http/endpoints/login.go b/app/http/endpoints/login.go
new file mode 100644
index 0000000..d10e2fb
--- /dev/null
+++ b/app/http/endpoints/login.go
@@ -0,0 +1,20 @@
+package endpoints
+
+import (
+ "fmt"
+ "github.com/TicketsBot/GoPanel/config"
+ "github.com/gin-gonic/contrib/sessions"
+ "github.com/gin-gonic/gin"
+ "net/url"
+)
+
+func LoginHandler(ctx *gin.Context) {
+ store := sessions.Default(ctx)
+ if store == nil {
+ return
+ }
+ defer store.Save()
+
+ redirect := url.QueryEscape(fmt.Sprintf("%s/callback", config.Conf.Server.BaseUrl))
+ ctx.Redirect(302, fmt.Sprintf("https://discordapp.com/oauth2/authorize?response_type=code&redirect_uri=%s&scope=identify+guilds&client_id=%d", redirect, config.Conf.Oauth.Id))
+}
diff --git a/app/http/layouts.go b/app/http/layouts.go
new file mode 100644
index 0000000..f866501
--- /dev/null
+++ b/app/http/layouts.go
@@ -0,0 +1,25 @@
+package http
+
+import (
+ "github.com/TicketsBot/GoPanel/app/http/template"
+)
+
+type Layout string
+
+const(
+ Main Layout = "main"
+)
+
+var(
+ layouts = map[string]template.Layout{
+ Main.ToString(): template.LoadLayout(Main.ToString()),
+ }
+)
+
+func (l Layout) ToString() string {
+ return string(l)
+}
+
+func (l Layout) GetInstance() template.Layout {
+ return layouts[l.ToString()]
+}
diff --git a/app/http/server.go b/app/http/server.go
new file mode 100644
index 0000000..04822d2
--- /dev/null
+++ b/app/http/server.go
@@ -0,0 +1,50 @@
+package http
+
+import (
+ "fmt"
+ "github.com/TicketsBot/GoPanel/app/http/endpoints"
+ "github.com/TicketsBot/GoPanel/config"
+ "github.com/gin-contrib/static"
+ "github.com/gin-gonic/contrib/sessions"
+ "github.com/gin-gonic/gin"
+ "log"
+)
+
+func StartServer() {
+ log.Println("Starting HTTP server")
+
+ router := gin.Default()
+
+ // Sessions
+ store, err := sessions.NewRedisStore(
+ config.Conf.Server.Session.Threads,
+ "tcp", fmt.Sprintf("%s:%d", config.Conf.Redis.Host, config.Conf.Redis.Port),
+ config.Conf.Redis.Password,
+ []byte(config.Conf.Server.Session.Secret))
+ if err != nil {
+ panic(err)
+ }
+ router.Use(sessions.Sessions("panel", store))
+
+ // Handle static asset requests
+ router.Use(static.Serve("/assets/", static.LocalFile("./public/static", false)))
+
+ // Root
+ router.GET("/", func(c *gin.Context) {
+ endpoints.IndexHandler(c)
+ })
+
+ // /login
+ router.GET("/login", func(c *gin.Context) {
+ endpoints.LoginHandler(c)
+ })
+
+ // /callback
+ router.GET("/callback", func(c *gin.Context) {
+ endpoints.CallbackHandler(c)
+ })
+
+ if err := router.Run(config.Conf.Server.Host); err != nil {
+ panic(err)
+ }
+}
diff --git a/app/http/template/layout.go b/app/http/template/layout.go
new file mode 100644
index 0000000..10ea26f
--- /dev/null
+++ b/app/http/template/layout.go
@@ -0,0 +1,22 @@
+package template
+
+import (
+ "fmt"
+ "github.com/TicketsBot/GoPanel/utils"
+)
+
+type Layout struct {
+ Name string
+ Content string
+}
+
+func LoadLayout(name string) Layout {
+ content, err := utils.ReadFile(fmt.Sprintf("./public/templates/layouts/%s.mustache", name)); if err != nil {
+ panic(err)
+ }
+
+ return Layout{
+ Name: name,
+ Content: content,
+ }
+}
diff --git a/app/http/template/template.go b/app/http/template/template.go
new file mode 100644
index 0000000..c994c2c
--- /dev/null
+++ b/app/http/template/template.go
@@ -0,0 +1,27 @@
+package template
+
+import (
+ "fmt"
+ "github.com/TicketsBot/GoPanel/utils"
+ "github.com/hoisie/mustache"
+)
+
+type Template struct {
+ Layout Layout
+ Content string
+}
+
+func LoadTemplate(layout Layout, name string) Template {
+ content, err := utils.ReadFile(fmt.Sprintf("./public/templates/views/%s.mustache", name)); if err != nil {
+ panic(err)
+ }
+
+ return Template{
+ Layout: layout,
+ Content: content,
+ }
+}
+
+func (t *Template) Render(context ...interface{}) string {
+ return mustache.RenderInLayout(t.Content, t.Layout.Content, context)
+}
diff --git a/app/http/templates.go b/app/http/templates.go
new file mode 100644
index 0000000..b817a41
--- /dev/null
+++ b/app/http/templates.go
@@ -0,0 +1,28 @@
+package http
+
+import "github.com/TicketsBot/GoPanel/app/http/template"
+
+type Template string
+
+const(
+ Index Template = "index"
+)
+
+var(
+ templates = map[string]template.Template{
+ Index.ToString(): template.LoadTemplate(Main.GetInstance(), Index.ToString()),
+ }
+)
+
+func (t Template) ToString() string {
+ return string(t)
+}
+
+func (t Template) GetInstance() template.Template {
+ return templates[t.ToString()]
+}
+
+func (t Template) Render(context ...interface{}) string {
+ temp := t.GetInstance()
+ return temp.Render(context)
+}
diff --git a/cmd/panel/main.go b/cmd/panel/main.go
index e8f78df..7dba0d3 100644
--- a/cmd/panel/main.go
+++ b/cmd/panel/main.go
@@ -1,7 +1,17 @@
package main
-import "github.com/TicketsBot/PanelV2/config"
+import (
+ "github.com/TicketsBot/GoPanel/app/http"
+ "github.com/TicketsBot/GoPanel/config"
+ "github.com/TicketsBot/GoPanel/database"
+ "math/rand"
+ "time"
+)
func main() {
+ rand.Seed(time.Now().UnixNano() % 3497)
+
config.LoadConfig()
+ database.ConnectToDatabase()
+ http.StartServer()
}
diff --git a/config.toml.example b/config.toml.example
index 742b39b..0525770 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -6,22 +6,22 @@ mainSite="https://ticketsbot.net"
window=10
max=600
[server.session]
- database="session"
+ threads=10
+ secret="secret"
[oauth]
-id=1
-secret="secret"
+id=
+secret=""
+redirectUri=""
[mariadb]
host="127.0.0.1"
-username="root"
-password="root"
+username="ryan"
+password="ryan"
database="tickets"
threads=5
-[bot]
-key=""
-httpServers=[]
-
[redis]
-uri="redis://:pwd@127.0.0.1:6379/0"
+host="127.0.0.1"
+port=6379
+password=""
diff --git a/config/config.go b/config/config.go
index 92a7ae1..3587882 100644
--- a/config/config.go
+++ b/config/config.go
@@ -9,6 +9,7 @@ type(
Config struct {
Server Server
Oauth Oauth
+ MariaDB MariaDB
Bot Bot
Redis Redis
}
@@ -27,12 +28,14 @@ type(
}
Session struct {
- Database string
+ Threads int
+ Secret string
}
Oauth struct {
Id int64
Secret string
+ RedirectUri string
}
MariaDB struct {
@@ -49,7 +52,9 @@ type(
}
Redis struct {
- Uri string
+ Host string
+ Port int
+ Password string
}
)
diff --git a/database/database.go b/database/database.go
new file mode 100644
index 0000000..4643896
--- /dev/null
+++ b/database/database.go
@@ -0,0 +1,31 @@
+package database
+
+import (
+ "fmt"
+ "github.com/TicketsBot/GoPanel/config"
+ _ "github.com/go-sql-driver/mysql"
+ "github.com/jinzhu/gorm"
+)
+
+var(
+ database **gorm.DB
+)
+
+func ConnectToDatabase() {
+ uri := fmt.Sprintf(
+ "%s:%s@tcp(%s:3306)/%s?charset=utf8mb4&parseTime=True&loc=Local",
+ config.Conf.MariaDB.Username,
+ config.Conf.MariaDB.Password,
+ config.Conf.MariaDB.Host,
+ config.Conf.MariaDB.Database,
+ )
+
+ db, err := gorm.Open("mysql", uri); if err != nil {
+ panic(err)
+ }
+
+ db.DB().SetMaxOpenConns(config.Conf.MariaDB.Threads)
+ db.DB().SetMaxIdleConns(0)
+
+ database = &db
+}
diff --git a/http/server.go b/http/server.go
deleted file mode 100644
index 3760de2..0000000
--- a/http/server.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package http
-
-import (
- "github.com/TicketsBot/PanelV2/config"
- "github.com/qiangxue/fasthttp-routing"
- "github.com/valyala/fasthttp"
- "log"
-)
-
-func StartServer() {
- log.Println("Starting HTTP server")
-
- router := routing.New()
-
- err := fasthttp.ListenAndServe(config.Conf.Server.Host, router.HandleRequest); if err != nil {
- panic(err)
- }
-}
diff --git a/public/templates/layouts/main.mustache b/public/templates/layouts/main.mustache
new file mode 100644
index 0000000..962a021
--- /dev/null
+++ b/public/templates/layouts/main.mustache
@@ -0,0 +1,42 @@
+
+
+
+ Tickets | A Discord Support Manager Bot
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{{body}}}
+
+
diff --git a/public/templates/views/index.mustache b/public/templates/views/index.mustache
new file mode 100644
index 0000000..553d994
--- /dev/null
+++ b/public/templates/views/index.mustache
@@ -0,0 +1,23 @@
+
+
+
+ {{#if isNotAdmin}}
+
+ You are not the admin of any guilds that the bot is in. Click below to invite the bot:
+
+ Invite
+
+ {{else}}
+
+ Select a server to manage below
+
+
+
+ {{#each guilds}}
+ - {{name}}
+ {{/each}}
+
+ {{/if}}
+
+
+
diff --git a/public/templates/views/logs.mustache b/public/templates/views/logs.mustache
new file mode 100644
index 0000000..0a56239
--- /dev/null
+++ b/public/templates/views/logs.mustache
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+ Ticket ID |
+ User |
+ User ID |
+ Log URL |
+
+
+
+ {{#each logs}}
+ {{{baseUrl}}}
+
+ {{TICKETID}} |
+ {{USERNAME}} |
+ {{USERID}} |
+ {{UUID}} |
+
+ {{/each}}
+
+
+
+
+
+
+
+
+
diff --git a/public/templates/views/settings.mustache b/public/templates/views/settings.mustache
new file mode 100644
index 0000000..1894889
--- /dev/null
+++ b/public/templates/views/settings.mustache
@@ -0,0 +1,84 @@
+
+
+
+
+
diff --git a/utils/discord/auth.go b/utils/discord/auth.go
new file mode 100644
index 0000000..5dac8d8
--- /dev/null
+++ b/utils/discord/auth.go
@@ -0,0 +1,113 @@
+package discord
+
+import (
+ "bytes"
+ "encoding/json"
+ "github.com/TicketsBot/GoPanel/config"
+ "github.com/pasztorpisti/qs"
+ "io/ioutil"
+ "net/http"
+ "strconv"
+ "time"
+)
+
+type(
+ TokenData struct {
+ ClientId string `qs:"client_id"`
+ ClientSecret string `qs:"client_secret"`
+ GrantType string `qs:"grant_type"`
+ Code string `qs:"code"`
+ RedirectUri string `qs:"redirect_uri"`
+ Scope string `qs:"scope"`
+ }
+
+ RefreshData struct {
+ ClientId string `qs:"client_id"`
+ ClientSecret string `qs:"client_secret"`
+ GrantType string `qs:"grant_type"`
+ RefreshToken string `qs:"refresh_token"`
+ RedirectUri string `qs:"redirect_uri"`
+ Scope string `qs:"scope"`
+ }
+
+ TokenResponse struct {
+ AccessToken string `json:"access_token"`
+ TokenType string `json:"token_type"`
+ ExpiresIn int `json:"expires_in"`
+ RefreshToken string `json:"refresh_token"`
+ Scope string `json:"scope"`
+ }
+)
+
+const TokenEndpoint = "https://discordapp.com/api/oauth2/token"
+
+func AccessToken(code string) (TokenResponse, error) {
+ data := TokenData{
+ ClientId: strconv.Itoa(int(config.Conf.Oauth.Id)),
+ ClientSecret: config.Conf.Oauth.Secret,
+ GrantType: "authorization_code",
+ Code: code,
+ RedirectUri: config.Conf.Oauth.RedirectUri,
+ Scope: "identify guilds",
+ }
+
+ res, err := tokenPost(data); if err != nil {
+ return TokenResponse{}, err
+ }
+
+ var unmarshalled TokenResponse
+ if err = json.Unmarshal(res, &unmarshalled); err != nil {
+ return TokenResponse{}, err
+ }
+
+ return unmarshalled, nil
+}
+
+func RefreshToken(refreshToken string) (TokenResponse, error) {
+ data := RefreshData{
+ ClientId: strconv.Itoa(int(config.Conf.Oauth.Id)),
+ ClientSecret: config.Conf.Oauth.Secret,
+ GrantType: "refresh_token",
+ RefreshToken: refreshToken,
+ RedirectUri: config.Conf.Oauth.RedirectUri,
+ Scope: "identify guilds",
+ }
+
+ res, err := tokenPost(data); if err != nil {
+ return TokenResponse{}, err
+ }
+
+ var unmarshalled TokenResponse
+ if err = json.Unmarshal(res, &unmarshalled); err != nil {
+ return TokenResponse{}, err
+ }
+
+ return unmarshalled, nil
+}
+
+func tokenPost(body ...interface{}) ([]byte, error) {
+ str, err := qs.Marshal(body[0]); if err != nil {
+ return nil, err
+ }
+ encoded := []byte(str)
+
+ req, err := http.NewRequest("POST", TokenEndpoint, bytes.NewBuffer([]byte(encoded))); if err != nil {
+ return nil, err
+ }
+
+ req.Header.Set("Content-Type", string(ApplicationFormUrlEncoded))
+
+ client := &http.Client{}
+ client.Timeout = 3 * time.Second
+
+ res, err := client.Do(req); if err != nil {
+ return nil, err
+ }
+
+ defer res.Body.Close()
+ content, err := ioutil.ReadAll(res.Body); if err != nil {
+ return nil, err
+ }
+
+ return content, nil
+}
diff --git a/utils/discord/endpoints.go b/utils/discord/endpoints.go
new file mode 100644
index 0000000..a934711
--- /dev/null
+++ b/utils/discord/endpoints.go
@@ -0,0 +1,104 @@
+package discord
+
+import (
+ "bytes"
+ "encoding/json"
+ "github.com/gin-gonic/contrib/sessions"
+ "github.com/pasztorpisti/qs"
+ "github.com/pkg/errors"
+ "io/ioutil"
+ "net/http"
+ "time"
+)
+
+type RequestType string
+type ContentType string
+
+const(
+ GET RequestType = "GET"
+ POST RequestType = "POST"
+ PATCH RequestType = "PATCH"
+
+ ApplicationJson ContentType = "application/json"
+ ApplicationFormUrlEncoded ContentType = "application/x-www-form-urlencoded"
+
+ BASE_URL = "https://discordapp.com/api/v6"
+)
+
+type Endpoint struct {
+ RequestType RequestType
+ Endpoint string
+}
+
+func (e *Endpoint) Request(store sessions.Session, contentType *ContentType, body interface{}, response interface{}) error {
+ url := BASE_URL + e.Endpoint
+
+ // Create req
+ var req *http.Request
+ var err error
+ if body == nil || contentType == nil {
+ req, err = http.NewRequest(string(e.RequestType), url, nil)
+ } else {
+ // Encode body
+ var encoded []byte
+ if *contentType == ApplicationJson {
+ raw, err := json.Marshal(body); if err != nil {
+ return err
+ }
+ encoded = raw
+ } else if *contentType == ApplicationFormUrlEncoded {
+ str, err := qs.Marshal(body); if err != nil {
+ return err
+ }
+ encoded = []byte(str)
+ }
+
+ // Create req
+ req, err = http.NewRequest(string(e.RequestType), url, bytes.NewBuffer(encoded))
+ }
+
+ if err != nil {
+ return err
+ }
+
+ // Set content type and user agent
+ if contentType != nil {
+ req.Header.Set("Content-Type", string(*contentType))
+ }
+ req.Header.Set("User-Agent", "DiscordBot (https://github.com/TicketsBot/GoPanel 1.0.0)")
+
+ // Auth
+ accessToken := store.Get("access_token").(string)
+ expiry := store.Get("expiry").(int64)
+ refreshToken := store.Get("refresh_token").(string)
+
+ // Check if needs refresh
+ if (time.Now().UnixNano() / int64(time.Second)) > int64(expiry) {
+ res, err := RefreshToken(refreshToken); if err != nil {
+ store.Clear()
+ _ = store.Save()
+ return errors.New("Please login again!")
+ }
+
+ store.Set("access_token", res.AccessToken)
+ store.Set("expiry", (time.Now().UnixNano() / int64(time.Second)) + int64(res.ExpiresIn))
+ store.Set("refresh_token", res.RefreshToken)
+
+ accessToken = res.AccessToken
+ }
+ req.Header.Set("Authorization", "Bearer " + accessToken)
+
+ client := &http.Client{}
+ client.Timeout = 3 * time.Second
+
+ res, err := client.Do(req); if err != nil {
+ return err
+ }
+ defer res.Body.Close()
+
+ content, err := ioutil.ReadAll(res.Body); if err != nil {
+ return err
+ }
+
+ return json.Unmarshal(content, response)
+}
diff --git a/utils/discord/endpoints/guild/getGuild.go b/utils/discord/endpoints/guild/getGuild.go
new file mode 100644
index 0000000..bd2da3e
--- /dev/null
+++ b/utils/discord/endpoints/guild/getGuild.go
@@ -0,0 +1,13 @@
+package guild
+
+import (
+ "fmt"
+ "github.com/TicketsBot/GoPanel/utils/discord"
+)
+
+func GetGuild(id int) discord.Endpoint {
+ return discord.Endpoint{
+ RequestType: discord.GET,
+ Endpoint: fmt.Sprintf("/guilds/%d", id),
+ }
+}
diff --git a/utils/discord/endpoints/user/currentUser.go b/utils/discord/endpoints/user/currentUser.go
new file mode 100644
index 0000000..742cdea
--- /dev/null
+++ b/utils/discord/endpoints/user/currentUser.go
@@ -0,0 +1,8 @@
+package user
+
+import "github.com/TicketsBot/GoPanel/utils/discord"
+
+var CurrentUser = discord.Endpoint{
+ RequestType: discord.GET,
+ Endpoint: "/users/@me",
+}
diff --git a/utils/discord/endpoints/user/currentUserGuilds.go b/utils/discord/endpoints/user/currentUserGuilds.go
new file mode 100644
index 0000000..b92bf83
--- /dev/null
+++ b/utils/discord/endpoints/user/currentUserGuilds.go
@@ -0,0 +1,8 @@
+package user
+
+import "github.com/TicketsBot/GoPanel/utils/discord"
+
+var CurrentUserGuilds = discord.Endpoint{
+ RequestType: discord.GET,
+ Endpoint: "/users/@me/guilds",
+}
diff --git a/utils/discord/objects/activity.go b/utils/discord/objects/activity.go
new file mode 100644
index 0000000..7d7e2c6
--- /dev/null
+++ b/utils/discord/objects/activity.go
@@ -0,0 +1,16 @@
+package objects
+
+type Activity struct {
+ Name string
+ Type int
+ Url string
+ Timestamps Timestamp
+ ApplicationId string
+ Details string
+ State string
+ Party Party
+ Assets Asset
+ Secrets Secret
+ Instance bool
+ Flags int
+}
diff --git a/utils/discord/objects/asset.go b/utils/discord/objects/asset.go
new file mode 100644
index 0000000..496884b
--- /dev/null
+++ b/utils/discord/objects/asset.go
@@ -0,0 +1,8 @@
+package objects
+
+type Asset struct {
+ LargeImage string
+ LargeText string
+ SmallImage string
+ SmallText string
+}
diff --git a/utils/discord/objects/channel.go b/utils/discord/objects/channel.go
new file mode 100644
index 0000000..46e10b4
--- /dev/null
+++ b/utils/discord/objects/channel.go
@@ -0,0 +1,22 @@
+package objects
+
+type Channel struct {
+ Id string
+ Type int
+ GuildId string
+ Position int
+ PermissionsOverwrites []Overwrite
+ Name string
+ Topic string
+ Nsfw bool
+ LastMessageId string
+ Bitrate int
+ userLimit int
+ RateLimitPerUser int
+ Recipients []User
+ Icon string
+ Ownerid string
+ ApplicationId string
+ ParentId string
+ LastPinTimestamp string
+}
diff --git a/utils/discord/objects/clientstatus.go b/utils/discord/objects/clientstatus.go
new file mode 100644
index 0000000..8baceae
--- /dev/null
+++ b/utils/discord/objects/clientstatus.go
@@ -0,0 +1,7 @@
+package objects
+
+type ClientStatus struct {
+ Desktop string
+ Mobile string
+ Web string
+}
diff --git a/utils/discord/objects/emoji.go b/utils/discord/objects/emoji.go
new file mode 100644
index 0000000..cb242c5
--- /dev/null
+++ b/utils/discord/objects/emoji.go
@@ -0,0 +1,11 @@
+package objects
+
+type Emoji struct {
+ Id string
+ Name string
+ Roles []string
+ User User
+ RequireColons bool
+ Managed bool
+ Animated bool
+}
diff --git a/utils/discord/objects/guild.go b/utils/discord/objects/guild.go
new file mode 100644
index 0000000..77e635d
--- /dev/null
+++ b/utils/discord/objects/guild.go
@@ -0,0 +1,40 @@
+package objects
+
+type Guild struct {
+ Id string
+ Name string
+ Icon string
+ Splash string
+ Owner bool
+ OwnerId string
+ Permissions int
+ Region string
+ AfkChannelid string
+ AfkTimeout int
+ EmbedEnabled bool
+ EmbedChannelId string
+ VerificationLevel int
+ DefaultMessageNotifications int
+ ExplicitContentFilter int
+ Roles []Role
+ Emojis []Emoji
+ Features []string
+ MfaLevel int
+ ApplicationId string
+ WidgetEnabled bool
+ WidgetChannelId string
+ SystemChannelId string
+ JoinedAt string
+ Large bool
+ Unavailable bool
+ MemberCount int
+ VoiceStates []VoiceState
+ Members []Member
+ Channels []Channel
+ Presences []Presence
+ MaxPresences int
+ Maxmembers int
+ VanityUrlCode string
+ Description string
+ Banner string
+}
diff --git a/utils/discord/objects/member.go b/utils/discord/objects/member.go
new file mode 100644
index 0000000..e49e43d
--- /dev/null
+++ b/utils/discord/objects/member.go
@@ -0,0 +1,10 @@
+package objects
+
+type Member struct {
+ User User
+ Nick string
+ Roles []string
+ JoinedAt string
+ Deaf bool
+ Mute bool
+}
diff --git a/utils/discord/objects/overwrite.go b/utils/discord/objects/overwrite.go
new file mode 100644
index 0000000..6852ac7
--- /dev/null
+++ b/utils/discord/objects/overwrite.go
@@ -0,0 +1,8 @@
+package objects
+
+type Overwrite struct {
+ Id string
+ Type string
+ Allow int
+ Deny int
+}
diff --git a/utils/discord/objects/party.go b/utils/discord/objects/party.go
new file mode 100644
index 0000000..dd11160
--- /dev/null
+++ b/utils/discord/objects/party.go
@@ -0,0 +1,6 @@
+package objects
+
+type Party struct {
+ Id string
+ Size []int
+}
diff --git a/utils/discord/objects/presence.go b/utils/discord/objects/presence.go
new file mode 100644
index 0000000..f8b7988
--- /dev/null
+++ b/utils/discord/objects/presence.go
@@ -0,0 +1,11 @@
+package objects
+
+type Presence struct {
+ User User
+ Roles []string
+ Game Activity
+ GuildId string
+ Status string
+ Activities []Activity
+ ClientStatus ClientStatus
+}
diff --git a/utils/discord/objects/role.go b/utils/discord/objects/role.go
new file mode 100644
index 0000000..9666ed4
--- /dev/null
+++ b/utils/discord/objects/role.go
@@ -0,0 +1,12 @@
+package objects
+
+type Role struct {
+ Id string
+ Name string
+ Color int
+ Hoist bool
+ Position int
+ Permissions int
+ Managed bool
+ Mentionable bool
+}
diff --git a/utils/discord/objects/secret.go b/utils/discord/objects/secret.go
new file mode 100644
index 0000000..6cfd0f5
--- /dev/null
+++ b/utils/discord/objects/secret.go
@@ -0,0 +1,7 @@
+package objects
+
+type Secret struct {
+ Join string
+ Spectate string
+ Match string
+}
diff --git a/utils/discord/objects/timestamp.go b/utils/discord/objects/timestamp.go
new file mode 100644
index 0000000..22bc1bd
--- /dev/null
+++ b/utils/discord/objects/timestamp.go
@@ -0,0 +1,6 @@
+package objects
+
+type Timestamp struct {
+ Start int
+ End int
+}
diff --git a/utils/discord/objects/user.go b/utils/discord/objects/user.go
new file mode 100644
index 0000000..02ddf3c
--- /dev/null
+++ b/utils/discord/objects/user.go
@@ -0,0 +1,12 @@
+package objects
+
+type User struct {
+ Id string
+ Username string
+ Discriminator string
+ Avatar string
+ Verified bool
+ Email string
+ Flags int
+ PremiumType int
+}
diff --git a/utils/discord/objects/voicestate.go b/utils/discord/objects/voicestate.go
new file mode 100644
index 0000000..d7521ac
--- /dev/null
+++ b/utils/discord/objects/voicestate.go
@@ -0,0 +1,14 @@
+package objects
+
+type VoiceState struct {
+ GuildId string
+ ChannelId string
+ UserId string
+ Member Member
+ SessionId string
+ Deaf bool
+ Mute bool
+ SelfDeaf bool
+ SelfMute bool
+ Suppress bool
+}
diff --git a/utils/fileutils.go b/utils/fileutils.go
new file mode 100644
index 0000000..dc2947b
--- /dev/null
+++ b/utils/fileutils.go
@@ -0,0 +1,11 @@
+package utils
+
+import "io/ioutil"
+
+func ReadFile(path string) (string, error) {
+ content, err := ioutil.ReadFile(path); if err != nil {
+ return "", err
+ }
+
+ return string(content), nil
+}
diff --git a/utils/sessionutils.go b/utils/sessionutils.go
new file mode 100644
index 0000000..8d36773
--- /dev/null
+++ b/utils/sessionutils.go
@@ -0,0 +1,9 @@
+package utils
+
+import (
+ "github.com/gin-gonic/contrib/sessions"
+)
+
+func IsLoggedIn(store sessions.Session) bool {
+ return store.Get("access_token") != nil && store.Get("expiry") != nil && store.Get("refresh_token") != nil && store.Get("userid") != nil && store.Get("name") != nil
+}
diff --git a/utils/stringutils.go b/utils/stringutils.go
new file mode 100644
index 0000000..4abd468
--- /dev/null
+++ b/utils/stringutils.go
@@ -0,0 +1,13 @@
+package utils
+
+import "math/rand"
+
+var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
+
+func RandStringRunes(length int) string {
+ b := make([]rune, length)
+ for i := range b {
+ b[i] = letterRunes[rand.Intn(len(letterRunes))]
+ }
+ return string(b)
+}