diff --git a/auth.go b/auth.go new file mode 100644 index 00000000..a79088c9 --- /dev/null +++ b/auth.go @@ -0,0 +1,30 @@ +package main + +import ( + "encoding/json" + "io/ioutil" +) + +// APIKeys ... +type APIKeys struct { + Google struct { + ID string `json:"id"` + Secret string `json:"secret"` + } `json:"google"` + + Facebook struct { + ID string `json:"id"` + Secret string `json:"secret"` + } `json:"facebook"` +} + +var apiKeys APIKeys + +func init() { + data, _ := ioutil.ReadFile("security/api-keys.json") + err := json.Unmarshal(data, &apiKeys) + + if err != nil { + panic(err) + } +} diff --git a/google.go b/google.go index 519e8584..feff0d8f 100644 --- a/google.go +++ b/google.go @@ -12,14 +12,6 @@ import ( "golang.org/x/oauth2/google" ) -// APIKeys ... -type APIKeys struct { - Google struct { - ID string `json:"id"` - Secret string `json:"secret"` - } `json:"google"` -} - // GoogleUser is the user data we receive from Google type GoogleUser struct { Sub string `json:"sub"` @@ -35,13 +27,9 @@ type GoogleUser struct { // EnableGoogleLogin enables Google login for the app. func EnableGoogleLogin(app *aero.Application) { - var api APIKeys - data, _ := ioutil.ReadFile("security/api-keys.json") - json.Unmarshal(data, &api) - conf := &oauth2.Config{ - ClientID: api.Google.ID, - ClientSecret: api.Google.Secret, + ClientID: apiKeys.Google.ID, + ClientSecret: apiKeys.Google.Secret, RedirectURL: "https://beta.notify.moe/auth/google/callback", Scopes: []string{ "https://www.googleapis.com/auth/userinfo.email", @@ -75,6 +63,7 @@ func EnableGoogleLogin(app *aero.Application) { // Construct the OAuth client client := conf.Client(oauth2.NoContext, token) + // Fetch user data from Google resp, err := client.Get("https://www.googleapis.com/oauth2/v3/userinfo") if err != nil { @@ -84,6 +73,7 @@ func EnableGoogleLogin(app *aero.Application) { defer resp.Body.Close() data, _ := ioutil.ReadAll(resp.Body) + // Construct a GoogleUser object var googleUser GoogleUser err = json.Unmarshal(data, &googleUser) @@ -91,6 +81,7 @@ func EnableGoogleLogin(app *aero.Application) { return ctx.Error(http.StatusBadRequest, "Failed parsing user data (JSON)", err) } + // Try to find an existing user by the associated e-mail address email := googleUser.Email user, getErr := arn.GetUserByEmail(email) @@ -98,8 +89,10 @@ func EnableGoogleLogin(app *aero.Application) { return ctx.Error(http.StatusForbidden, "Email not registered", err) } + // Login session.Set("userId", user.ID) + // Redirect back to frontpage return ctx.Redirect("/") }) } diff --git a/logger.go b/logger.go index f900259d..a3a71fbb 100644 --- a/logger.go +++ b/logger.go @@ -1,6 +1,8 @@ package main import ( + "net/http" + "os" "strconv" "strings" "time" @@ -12,10 +14,10 @@ import ( func init() { err := log.NewChannel("error") err.AddOutput(log.File("logs/error.log")) - // err.AddOutput(os.Stderr) + err.AddOutput(os.Stderr) - web := log.NewChannel("web") - web.AddOutput(log.File("logs/request.log")) + request := log.NewChannel("request") + request.AddOutput(log.File("logs/request.log")) app.Use(func(ctx *aero.Context, next func()) { start := time.Now() @@ -25,11 +27,20 @@ func init() { responseTimeString = strings.Repeat(" ", 8-len(responseTimeString)) + responseTimeString // Log every request - web.Info(ctx.RealIP(), ctx.StatusCode, responseTimeString, ctx.URI()) + request.Info(ctx.RealIP(), ctx.StatusCode, responseTimeString, ctx.URI()) + + // Log all requests that failed + switch ctx.StatusCode { + case http.StatusOK, http.StatusFound, http.StatusMovedPermanently, http.StatusPermanentRedirect, http.StatusTemporaryRedirect: + // Ok. + + default: + err.Error(http.StatusText(ctx.StatusCode), ctx.RealIP(), ctx.StatusCode, responseTimeString, ctx.URI()) + } // Notify us about long requests - if responseTime >= 100*time.Millisecond { - err.Error("Unusually long response time", ctx.RealIP(), ctx.StatusCode, responseTimeString, ctx.URI()) + if responseTime >= 200*time.Millisecond { + err.Error("Long response time", ctx.RealIP(), ctx.StatusCode, responseTimeString, ctx.URI()) } }) } diff --git a/mixins/ForumTags.pixy b/mixins/ForumTags.pixy new file mode 100644 index 00000000..252c40d7 --- /dev/null +++ b/mixins/ForumTags.pixy @@ -0,0 +1,12 @@ +component ForumTags + .forum-tags.light-button-group + ForumTag("All", "") + ForumTag("General", "/general") + ForumTag("News", "/news") + ForumTag("Anime", "/anime") + ForumTag("Updates", "/update") + ForumTag("Suggestions", "/suggestion") + ForumTag("Bugs", "/bug") + +component ForumTag(title string, suffix string) + a.light-button.forum-tag.ajax(href="/forum" + suffix)= title \ No newline at end of file diff --git a/pages/forum/forum.scarlet b/pages/forum/forum.scarlet index 2a0cbeb8..93f914fe 100644 --- a/pages/forum/forum.scarlet +++ b/pages/forum/forum.scarlet @@ -1,2 +1,7 @@ +.forum-tag + &.active + color white + background-color text-color + #load-more-threads margin-top 1rem \ No newline at end of file diff --git a/pages/forums/forums.pixy b/pages/forums/forums.pixy index 60e70e27..2372d037 100644 --- a/pages/forums/forums.pixy +++ b/pages/forums/forums.pixy @@ -1,20 +1,3 @@ component Forums h2.forum-header Forum - ForumTags - -component ForumTags - .forum-tags.light-button-group - ForumCategory("All", "") - ForumCategory("General", "/general") - ForumCategory("News", "/news") - ForumCategory("Anime", "/anime") - ForumCategory("Updates", "/update") - ForumCategory("Suggestions", "/suggestion") - ForumCategory("Bugs", "/bug") - -component ForumCategory(title string, suffix string) - a.light-button.ajax(href="/forum" + suffix)= title - //- a.grid-cell.ajax(href="/forum/" + category) - //- .grid-text - //- GridIcon(arn.GetForumIcon(category)) - //- span= title \ No newline at end of file + ForumTags \ No newline at end of file diff --git a/pages/profile/profile.pixy b/pages/profile/profile.pixy index bfecca98..fd4c67a7 100644 --- a/pages/profile/profile.pixy +++ b/pages/profile/profile.pixy @@ -1,6 +1,6 @@ component Profile(viewUser *arn.User, user *arn.User, animeList *arn.AnimeList, threads []*arn.Thread) .profile - img.profile-cover(src=viewUser.CoverImageURL()) + img.profile-cover(src=viewUser.CoverImageURL(), alt="Cover image") .image-container ProfileImage(viewUser)