diff --git a/Makefile b/Makefile index 242bca4..348464c 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ COMP_BIN := go build: mkdir -p dist/ - ${COMP_BIN} build -o "${BIN}" -ldflags="${LD_FLAGS}" ./cmd/gitea-tools + ${COMP_BIN} build -o "${BIN}" -ldflags="${LD_FLAGS}" ./cmd/melon-tools run: make build diff --git a/cmd/melon-tools/main.go b/cmd/melon-tools/main.go index 0f1bf27..a3ebf74 100644 --- a/cmd/melon-tools/main.go +++ b/cmd/melon-tools/main.go @@ -1,6 +1,7 @@ package main import ( + "code.mrmelon54.xyz/sean/melon-tools/module/discord" "code.mrmelon54.xyz/sean/melon-tools/module/gitea" "code.mrmelon54.xyz/sean/melon-tools/utils" "encoding/gob" @@ -16,8 +17,9 @@ import ( ) var ( - modules = map[string]utils.IModule{ - "/gitea": gitea.New(), + modules = []utils.IModule{ + gitea.New(), + discord.New(), } sessionStore = sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY"))) ) @@ -36,15 +38,17 @@ func main() { rw.Header().Set("Content-Type", "text/html") rw.WriteHeader(http.StatusOK) _, _ = rw.Write([]byte("Melon Tools
\n")) - _, _ = rw.Write([]byte("Gitea\n")) + for _, v := range modules { + _, _ = rw.Write([]byte(fmt.Sprintf("%s
\n", v.GetEndpoint(), v.GetName()))) + } }) gob.Register(uuid.UUID{}) - for k, v := range modules { - router.HandleFunc(k, func(rw http.ResponseWriter, req *http.Request) { - http.Redirect(rw, req, k+"/", http.StatusTemporaryRedirect) + for _, v := range modules { + router.HandleFunc(v.GetEndpoint(), func(rw http.ResponseWriter, req *http.Request) { + http.Redirect(rw, req, v.GetEndpoint()+"/", http.StatusTemporaryRedirect) }) - v.SetupModule(router.PathPrefix(k).Subrouter(), stateManager.sessionWrapper) + v.SetupModule(router.PathPrefix(v.GetEndpoint()).Subrouter(), stateManager.sessionWrapper) } s := &http.Server{ diff --git a/go.mod b/go.mod index 848803d..6a688c5 100644 --- a/go.mod +++ b/go.mod @@ -12,10 +12,14 @@ require ( ) require ( + github.com/bwmarrin/discordgo v0.24.0 // indirect github.com/golang/protobuf v1.4.2 // indirect github.com/gorilla/securecookie v1.1.1 // indirect + github.com/gorilla/websocket v1.4.2 // indirect github.com/hashicorp/go-version v1.2.1 // indirect + golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect google.golang.org/appengine v1.6.6 // indirect google.golang.org/protobuf v1.25.0 // indirect ) diff --git a/go.sum b/go.sum index 44a6211..d858c8c 100644 --- a/go.sum +++ b/go.sum @@ -36,6 +36,8 @@ code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMV dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/bwmarrin/discordgo v0.24.0 h1:Gw4MYxqHdvhO99A3nXnSLy97z5pmIKHZVJ1JY5ZDPqY= +github.com/bwmarrin/discordgo v0.24.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -106,6 +108,8 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -139,6 +143,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -195,6 +201,7 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -237,8 +244,11 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/module/discord/guild-icon.go b/module/discord/guild-icon.go new file mode 100644 index 0000000..cb96a38 --- /dev/null +++ b/module/discord/guild-icon.go @@ -0,0 +1,17 @@ +package discord + +import ( + "bytes" + "github.com/bwmarrin/discordgo" + "image" +) + +func getGuildIcon(s *discordgo.Session, guild *discordgo.UserGuild) (image.Image, error) { + body, err := s.RequestWithBucketID("GET", discordgo.EndpointGuildIcon(guild.ID, guild.Icon), nil, discordgo.EndpointGuildIcon(guild.ID, "")) + if err != nil { + return nil, nil + } + + img, _, err := image.Decode(bytes.NewReader(body)) + return img, err +} diff --git a/module/discord/main.go b/module/discord/main.go new file mode 100644 index 0000000..ca5e052 --- /dev/null +++ b/module/discord/main.go @@ -0,0 +1,235 @@ +package discord + +import ( + "bytes" + "code.mrmelon54.xyz/sean/melon-tools/utils" + "context" + "embed" + _ "embed" + "fmt" + "github.com/bwmarrin/discordgo" + "github.com/google/uuid" + "github.com/gorilla/mux" + "golang.org/x/oauth2" + "html/template" + "image" + "image/png" + "net/http" + "os" +) + +var ( + //go:embed pages/index.go.html + indexTemplate string + //go:embed pages/assets/icon + iconFiles embed.FS +) + +type Module struct { + sessionWrapper func(cb func(http.ResponseWriter, *http.Request, *utils.State)) func(rw http.ResponseWriter, req *http.Request) + oauthClient *oauth2.Config +} + +type discordKeyType int + +const ( + KeyOauthClient = discordKeyType(iota) + KeyUser + KeyState + KeyAccessToken + KeyRefreshToken +) + +func New() *Module { + return &Module{} +} + +func (m *Module) GetName() string { return "Discord" } +func (m *Module) GetEndpoint() string { return "/discord" } + +func (m *Module) SetupModule(router *mux.Router, f func(cb func(http.ResponseWriter, *http.Request, *utils.State)) func(rw http.ResponseWriter, req *http.Request)) { + m.sessionWrapper = f + m.oauthClient = &oauth2.Config{ + ClientID: os.Getenv("DISCORD_CLIENT_ID"), + ClientSecret: os.Getenv("DISCORD_CLIENT_SECRET"), + Scopes: []string{"identify", "guilds", "connections", "email"}, + Endpoint: oauth2.Endpoint{ + AuthURL: "https://discord.com/oauth2/authorize", + TokenURL: "https://discord.com/api/oauth2/token", + }, + RedirectURL: os.Getenv("DISCORD_REDIRECT_URL"), + } + router.HandleFunc("/", m.getClient(m.homepage)) + router.HandleFunc("/login", m.sessionWrapper(m.loginPage)) + router.HandleFunc("/user/avatar/{userId}/{avatarId}", m.getClient(m.userAvatar)) + router.HandleFunc("/guild/icon/{guildId}/{iconId}", m.getClient(m.guildIcon)) + router.PathPrefix("/assets/icon/{name}.svg").HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + b, err := iconFiles.ReadFile("pages/assets/icon/" + vars["name"] + ".svg") + if err != nil { + rw.WriteHeader(http.StatusNotFound) + } else { + rw.Header().Set("Content-Type", "image/svg+xml") + rw.WriteHeader(http.StatusOK) + _, _ = rw.Write(b) + } + }) +} + +func (m *Module) getClient(cb func(http.ResponseWriter, *http.Request, *utils.State, *discordgo.Session)) func(rw http.ResponseWriter, req *http.Request) { + return m.sessionWrapper(func(rw http.ResponseWriter, req *http.Request, state *utils.State) { + if v, ok := utils.GetStateValue[*discordgo.Session](state, KeyOauthClient); ok { + cb(rw, req, state, v) + return + } + http.Redirect(rw, req, "/discord/login", http.StatusTemporaryRedirect) + }) +} + +func (m *Module) homepage(rw http.ResponseWriter, req *http.Request, state *utils.State, discordClient *discordgo.Session) { + myUser, err := discordClient.User("@me") + if err != nil { + state.Del(KeyOauthClient) + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + myGuilds, err := discordClient.UserGuilds(100, "", "") + if err != nil { + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + myConns, err := discordClient.UserConnections() + if err != nil { + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + + tmp, err := template.New("homepage").Funcs(template.FuncMap{ + "checkFlag": func(a discordgo.UserFlags, b int) bool { return (int(a) & b) != 0 }, + "connectedLink": connectedLinkFunc, + }).Parse(indexTemplate) + if err != nil { + fmt.Println("Template parse error:", err) + return + } + + guildIcons := make([]template.HTMLAttr, len(myGuilds)) + for i, j := range myGuilds { + guildIcons[i] = template.HTMLAttr(fmt.Sprintf("src=\"/discord/guild/icon/%s/%s\"", j.ID, j.Icon)) + } + + err = tmp.Execute(rw, struct { + User *discordgo.User + Avatar template.HTMLAttr + Guilds []*discordgo.UserGuild + GuildIcons []template.HTMLAttr + Connections []*discordgo.UserConnection + }{ + User: myUser, + Avatar: template.HTMLAttr(fmt.Sprintf("src=\"/discord/user/avatar/%s/%s\"", myUser.ID, myUser.Avatar)), + Guilds: myGuilds, + GuildIcons: guildIcons, + Connections: myConns, + }) + if err != nil { + fmt.Println("Template execute error:", err) + return + } +} + +func (m *Module) loginPage(rw http.ResponseWriter, req *http.Request, state *utils.State) { + if myUser, ok := utils.GetStateValue[*string](state, KeyUser); ok { + if myUser != nil { + http.Redirect(rw, req, "/discord", http.StatusTemporaryRedirect) + return + } + } + + if flowState, ok := utils.GetStateValue[uuid.UUID](state, KeyState); ok { + q := req.URL.Query() + if q.Has("code") && q.Has("state") { + if q.Get("state") == flowState.String() { + exchange, err := m.oauthClient.Exchange(context.Background(), q.Get("code")) + if err != nil { + fmt.Println("Exchange token error:", err) + return + } + c, err := discordgo.New("Bearer " + exchange.AccessToken) + if err != nil { + fmt.Println("Create client error:", err) + return + } + state.Put(KeyOauthClient, c) + state.Put(KeyAccessToken, exchange.AccessToken) + state.Put(KeyRefreshToken, exchange.RefreshToken) + http.Redirect(rw, req, "/discord", http.StatusTemporaryRedirect) + return + } + http.Error(rw, "OAuth flow state doesn't match\n", http.StatusBadRequest) + return + } + } + + flowState := uuid.New() + state.Put(KeyState, flowState) + + http.Redirect(rw, req, m.oauthClient.AuthCodeURL(flowState.String(), oauth2.AccessTypeOffline), http.StatusTemporaryRedirect) +} + +func (m *Module) userAvatar(rw http.ResponseWriter, req *http.Request, state *utils.State, discordClient *discordgo.Session) { + vars := mux.Vars(req) + body, err := discordClient.RequestWithBucketID("GET", discordgo.EndpointUserAvatar(vars["userId"], vars["avatarId"]), nil, discordgo.EndpointUserAvatar("", "")) + if err != nil { + return + } + + rw.Header().Set("Content-Type", "image/png") + rw.WriteHeader(200) + + myAvatar, _, err := image.Decode(bytes.NewReader(body)) + err = png.Encode(rw, myAvatar) + if err != nil { + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } +} + +func (m *Module) guildIcon(rw http.ResponseWriter, req *http.Request, state *utils.State, discordClient *discordgo.Session) { + vars := mux.Vars(req) + body, err := discordClient.RequestWithBucketID("GET", discordgo.EndpointGuildIcon(vars["guildId"], vars["iconId"]), nil, discordgo.EndpointGuildIcon(vars["guildId"], "")) + if err != nil { + return + } + + rw.Header().Set("Content-Type", "image/png") + rw.WriteHeader(http.StatusOK) + + myAvatar, _, err := image.Decode(bytes.NewReader(body)) + err = png.Encode(rw, myAvatar) + if err != nil { + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } +} + +func connectedLinkFunc(a *discordgo.UserConnection) string { + switch a.Type { + case "github": + return "https://github.com/" + a.Name + case "reddit": + return "https://www.reddit.com/u/" + a.Name + case "spotify": + return "https://open.spotify.com/user/" + a.ID + case "steam": + return "https://steamcommunity.com/profiles/" + a.ID + case "twitch": + return "https://www.twitch.tv/" + a.Name + case "twitter": + return "https://twitter.com/" + a.Name + case "xbox": + return "javascript:alert('No link to XBox profiles')" + case "youtube": + return "https://www.youtube.com/channel/" + a.ID + } + return "javascript:alert('Unknown profile type')" +} diff --git a/module/discord/pages/assets/icon/github.svg b/module/discord/pages/assets/icon/github.svg new file mode 100644 index 0000000..1734266 --- /dev/null +++ b/module/discord/pages/assets/icon/github.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/module/discord/pages/assets/icon/reddit.svg b/module/discord/pages/assets/icon/reddit.svg new file mode 100644 index 0000000..62ed78d --- /dev/null +++ b/module/discord/pages/assets/icon/reddit.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/module/discord/pages/assets/icon/spotify.svg b/module/discord/pages/assets/icon/spotify.svg new file mode 100644 index 0000000..901e15e --- /dev/null +++ b/module/discord/pages/assets/icon/spotify.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/module/discord/pages/assets/icon/steam.svg b/module/discord/pages/assets/icon/steam.svg new file mode 100644 index 0000000..a8df1ae --- /dev/null +++ b/module/discord/pages/assets/icon/steam.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/module/discord/pages/assets/icon/twitch.svg b/module/discord/pages/assets/icon/twitch.svg new file mode 100644 index 0000000..6f0a600 --- /dev/null +++ b/module/discord/pages/assets/icon/twitch.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/module/discord/pages/assets/icon/twitter.svg b/module/discord/pages/assets/icon/twitter.svg new file mode 100644 index 0000000..5ac575b --- /dev/null +++ b/module/discord/pages/assets/icon/twitter.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/module/discord/pages/assets/icon/xbox.svg b/module/discord/pages/assets/icon/xbox.svg new file mode 100644 index 0000000..472690a --- /dev/null +++ b/module/discord/pages/assets/icon/xbox.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/module/discord/pages/assets/icon/youtube.svg b/module/discord/pages/assets/icon/youtube.svg new file mode 100644 index 0000000..0e18462 --- /dev/null +++ b/module/discord/pages/assets/icon/youtube.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/module/discord/pages/index.go.html b/module/discord/pages/index.go.html new file mode 100644 index 0000000..2fa365c --- /dev/null +++ b/module/discord/pages/index.go.html @@ -0,0 +1,124 @@ + + + + Discord | Melon Tools + + + +

Discord | Melon Tools

+
+
+ {{with .User}} +

My User: {{.Username}}#{{.Discriminator}}

+ + {{end}} +
+
+ {{with .User.PublicFlags}} +

My Flags:

+ + {{end}} +
+
+

Connections ({{len .Connections}}):

+ +
+
+

Guilds ({{len .Guilds}}):

+
+ {{range $k, $v := .Guilds}} +
+
+
{{$v.Name}}
+
@*{{$v.ID}}
+
+ {{end}} +
+
+
+ + diff --git a/module/gitea/main.go b/module/gitea/main.go index 8e08ebf..bf38542 100644 --- a/module/gitea/main.go +++ b/module/gitea/main.go @@ -20,8 +20,8 @@ import ( var indexTemplate string type Module struct { - oauthClient *oauth2.Config sessionWrapper func(cb func(http.ResponseWriter, *http.Request, *utils.State)) func(rw http.ResponseWriter, req *http.Request) + oauthClient *oauth2.Config } type giteaKeyType int @@ -39,8 +39,11 @@ func New() *Module { return &Module{} } -func (m *Module) SetupModule(router *mux.Router, cb func(cb func(http.ResponseWriter, *http.Request, *utils.State)) func(rw http.ResponseWriter, req *http.Request)) { - m.sessionWrapper = cb +func (m *Module) GetName() string { return "Gitea" } +func (m *Module) GetEndpoint() string { return "/gitea" } + +func (m *Module) SetupModule(router *mux.Router, f func(cb func(http.ResponseWriter, *http.Request, *utils.State)) func(rw http.ResponseWriter, req *http.Request)) { + m.sessionWrapper = f m.oauthClient = &oauth2.Config{ ClientID: os.Getenv("GITEA_CLIENT_ID"), ClientSecret: os.Getenv("GITEA_CLIENT_SECRET"), diff --git a/module/gitea/pages/index.go.html b/module/gitea/pages/index.go.html index a196799..4c9b4a5 100644 --- a/module/gitea/pages/index.go.html +++ b/module/gitea/pages/index.go.html @@ -1,5 +1,5 @@ - + Gitea | Melon Tools