Add login support

This commit is contained in:
2020-09-05 16:25:29 +10:00
parent c263cdd381
commit 7b0da3a5dc
11 changed files with 162 additions and 50 deletions
+16 -13
View File
@@ -43,14 +43,11 @@ const (
ColorSchemeBlue = ColorScheme("fill-opacity:1.00; fill:rgb(32, 99, 155);")
BadgeTypePrometheus = "PROMETHEUS"
pageViewsLabel = "Page Views"
radius = 0
fontSize = 12
textMarginX = 6.0
textMarginY = 14
badgeHeight = 20
textStyle = "text-anchor:start;font-size:12px;fill:white;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;"
badgeExpireSeconds = 10
labelWidthPortion = 0.65
metricRequestTimeout = 10 * time.Second
ErrorMessageInternalError = "Oops, there's something wrong, please try it again later."
)
@@ -190,17 +187,23 @@ func (handler *BadgesHandler) queryBadgeFromDB(queryName string) (*models.Badge,
return &badge, nil
}
// func (handler *BadgesHandler) MyBadges(c *gin.Context) {
// var currentUser *models.User
// userInterface, exists := c.Get("user")
// if !exists {
// logrus.Error("user cannot be found from context")
// c.JSON(http.StatusInternalServerError, gin.H{"msg": ErrorMessageInternalError})
// return
// }
// currentUser = userInterface.(*models.User)
func (handler *BadgesHandler) MyBadges(c *gin.Context) {
userInterface, exists := c.Get("currentUser")
if !exists {
logrus.Error("user cannot be found from context")
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"msg": ErrorMessageInternalError})
return
}
currentUser := userInterface.(models.User)
badges := make([]*models.Badge, 0)
// }
if err := handler.DB.Find(&badges, "user_id = ?", currentUser.ID).Error; err != nil {
sentry.CaptureException(err)
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"msg": ErrorMessageInternalError})
}
c.JSON(http.StatusOK, badges)
}
func (handler *BadgesHandler) CreateBadge(c *gin.Context) {
newID := NewULID()
+6 -1
View File
@@ -40,6 +40,7 @@ type UserAuthenticationRequest struct {
type UserInfo struct {
ID string `json:"id"`
GithubID string `json:"githubId"`
Token string `json:"token"`
}
func (usersHandler *UsersHandler) AuthRequired(c *gin.Context) {
@@ -124,7 +125,11 @@ func (usersHandler *UsersHandler) Authenticate(c *gin.Context) {
c.JSON(http.StatusInternalServerError, GeneralError{"internal error, please try it later"})
return
}
c.JSON(http.StatusOK, UserInfo{ID: user.ULID, GithubID: user.GithubID})
c.JSON(http.StatusOK, UserInfo{
ID: user.ULID,
GithubID: user.GithubID,
Token: user.Token.Token,
})
}
func validateUser(token string) bool {
+1
View File
@@ -88,6 +88,7 @@ func main() {
api.Use(userHandler.AuthRequired)
api.POST("/auth", userHandler.Authenticate)
api.POST("/badges", handler.CreateBadge)
api.GET("/badges", handler.MyBadges)
go func() {
http.Handle("/metrics", promhttp.Handler())
+7 -7
View File
@@ -7,11 +7,11 @@ import (
type Badge struct {
gorm.Model
Label string
ULID string `gorm:"column:ulid;type:varchar;not null;unique_index"`
Type string
User User
UserID int
Options *postgres.Jsonb
OptionStruct interface{} `gorm:"-"`
Label string `json:"label"`
ULID string `gorm:"column:ulid;type:varchar;not null;unique_index" json:"ulid"`
Type string `json:"type"`
User User `json:"-"`
UserID int `json:"userId"`
Options *postgres.Jsonb `json:"-"`
OptionStruct interface{} `gorm:"-"`
}
+36 -9
View File
@@ -7,7 +7,7 @@
<b-collapse id="nav-collapse" is-nav>
<b-navbar-nav>
<b-nav-item to="/badges" exact>
Badges
My badges
</b-nav-item>
</b-navbar-nav>
<b-navbar-nav class="ml-auto">
@@ -17,7 +17,13 @@
Logout
</b-dropdown-item>
</b-nav-item-dropdown>
<b-img :src="picture" class="mt-1" rounded="circle" width="30px" height="30px" />
<b-img
:src="picture"
class="mt-1"
rounded="circle"
width="30px"
height="30px"
/>
</template>
<template v-else>
<b-dropdown-item variant="light" to="/login">
@@ -31,9 +37,8 @@
<b-row class="row-space footer">
<b-col md="4" offset-md="4">
<span class="copyright">
© 2020 toozhao.com <img :src="myBadge" class="my-badge"/>
© 2020 toozhao.com <img :src="myBadge" class="my-badge" />
</span>
</b-col>
</b-row>
</b-overlay>
@@ -45,7 +50,27 @@ import { mapMutations } from "vuex";
import get from "lodash.get";
export default Vue.extend({
beforeMount() {
if (!this.$auth.loggedIn) {
return;
}
this.$store.dispatch("users/loginFromLocal")
if (this.$store.state.users.token === "") {
this.$store.dispatch("users/authenticate", {
name: this.currentUser.login,
githubId: this.currentUser.id,
githubUsername: this.currentUser.name,
githubAvatar: this.currentUser.avatar_url,
token: this.$auth.strategy.token.get().substring(7)
});
}
},
computed: {
currentUser() {
return this.$auth.user;
},
isLoading() {
return this.$store.state.loading.loading;
},
@@ -53,12 +78,14 @@ export default Vue.extend({
return this.$config.env === "production";
},
myBadge() {
return `${this.$config.myBadge}/green.svg`
return `${this.$config.myBadge}/green.svg`;
},
picture () {
return get(this.$auth.user, 'picture') || // OpenID
get(this.$auth.user, 'picture.data.url') || // Facebook graph API
get(this.$auth.user, 'avatar_url') // GitHub
picture() {
return (
get(this.$auth.user, "picture") || // OpenID
get(this.$auth.user, "picture.data.url") || // Facebook graph API
get(this.$auth.user, "avatar_url")
); // GitHub
}
}
});
+5
View File
@@ -10823,6 +10823,11 @@
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"dev": true
},
"moment": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz",
"integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ=="
},
"move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
+1
View File
@@ -20,6 +20,7 @@
"express-jwt": "^6.0.0",
"lodash": "^4.17.20",
"lodash.get": "^4.4.2",
"moment": "^2.27.0",
"nanoid": "^2.1.11",
"nuxt": "^2.14.4",
"nuxt-i18n": "^6.13.12"
+68 -8
View File
@@ -1,17 +1,77 @@
<template>
<div class="my-badges-container">
<div class="my-badges-container container">
<b-container fluid="lg">
<b-row>
<b-col lg="4" offset-lg="4">
Hello
<b-row class="badges ">
<b-col lg="12">
<b-card
border-variant="primary"
header-bg-variant="primary"
header-text-variant="white"
align="center"
:header="badge.label"
:sub-title="badgeCreated(badge.CreatedAt)"
bg-variant="light"
v-for="badge in badges"
:key="badge.ulid"
class="my-badge"
>
<b-card-text> </b-card-text>
<b-card-text>
<img :src="badgeUrl(badge)" class="my-badge" />
</b-card-text>
<a href="#" class="card-link" style="display:none"><svg></svg></a>
<b-link href="#" class="card-link" style="display:none"
>Another link</b-link
>
</b-card>
</b-col>
</b-row>
</b-container>
</div>
</template>
<script>
export default {
middleware: ['auth']
};
import moment from "moment";
import { mapMutations, mapActions } from "vuex";
export default {
middleware: ["auth"],
computed: {
badges() {
return this.$store.state.badges.badges;
}
},
mounted() {
this.$store.commit("loading/updateLoading");
if (this.$store.state.users.token === "") {
setTimeout(() => {
this.$store.dispatch("badges/getMyBadges", () => {
this.$store.commit("loading/updateLoading");
});
}, 2000);
} else {
this.$store.dispatch("badges/getMyBadges", () => {
this.$store.commit("loading/updateLoading");
});
}
},
methods: {
badgeCreated(createdAt) {
return `Created at: ${moment(createdAt).format("YYYY-MM-DD hh:mm:ss a")}`;
},
badgeUrl(badge) {
return `${this.$config.backendURL}/badges/${badge.ulid}/green.svg`;
}
}
};
</script>
<style lang="scss"></style>
<style lang="scss">
.my-badges-container {
.badges {
.my-badge {
margin-top: 4vh;
}
}
}
</style>
-11
View File
@@ -201,17 +201,6 @@ export default Vue.extend({
return this.$auth.user
}
},
mounted() {
if(this.$auth.loggedIn) {
this.$store.dispatch("users/authenticate", {
"name": this.currentUser.login,
"githubId": this.currentUser.id,
"githubUsername": this.currentUser.name,
"githubAvatar": this.currentUser.avatar_url,
"token": this.$auth.strategy.token.get().substring(7)
})
}
},
methods: {
isBadgeActive: function(color) {
return this.activeBadgeColor === color;
+11 -1
View File
@@ -1,10 +1,14 @@
export const state = () => ({
currentBadge: {}
currentBadge: {},
badges: []
});
export const mutations = {
updateBadge(state, badge) {
state.currentBadge = badge;
},
updateBadges(state, badges) {
state.badges = badges;
}
};
@@ -13,5 +17,11 @@ export const actions = {
const result = await this.$axios.$post("/api/badges");
context.commit("updateBadge", result);
callback();
},
async getMyBadges(context, callback) {
const result = await this.$axios.$get("/api/badges");
context.commit("updateBadges", result);
callback();
}
};
+11
View File
@@ -13,10 +13,20 @@ export const mutations = {
};
export const actions = {
loginFromLocal(context) {
var currentUserStr = localStorage.getItem("user");
if (currentUserStr === null || currentUserStr === "") {
return;
}
var currentUser = JSON.parse(currentUserStr);
context.commit("updateUser", currentUser);
context.commit("updateToken", currentUser.token);
},
async authenticate(context, requestBody, callback) {
const result = await this.$axios.$post("/api/auth", requestBody);
context.commit("updateUser", result);
context.commit("updateToken", requestBody.token);
localStorage.setItem("user", JSON.stringify(result));
if (!!callback && typeof callback === "function") {
callback();
@@ -25,6 +35,7 @@ export const actions = {
logout(context, callback) {
context.commit("updateUser", {});
context.commit("updateToken", "");
localStorage.removeItem("user");
if (!!callback && typeof callback === "function") {
callback();
}