Add feature toggle api, tried to reduce frontend size

This commit is contained in:
2021-01-26 23:23:00 +11:00
parent a6464748a3
commit 762ed49cf7
12 changed files with 158 additions and 46 deletions
+25
View File
@@ -0,0 +1,25 @@
package handlers
import (
"net/http"
"github.com/getsentry/sentry-go"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
"github.com/wahyd4/badger/models"
)
type FeatureTogglesHandler struct {
DB *gorm.DB
}
func (handler *FeatureTogglesHandler) Toggles(c *gin.Context) {
toggles := make([]*models.FeatureToggle, 0)
if err := handler.DB.Find(&toggles).Error; err != nil {
sentry.CaptureException(err)
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"msg": ErrorMessageInternalError})
}
c.JSON(http.StatusOK, toggles)
}
+1 -1
View File
@@ -20,7 +20,7 @@ const (
)
var (
NoAuthPaths = []string{"/api/badges", "/api/auth"}
NoAuthPaths = []string{"/api/badges", "/api/auth", "/api/toggles"}
)
type UsersHandler struct {
+3 -1
View File
@@ -60,6 +60,7 @@ func main() {
&models.Token{},
&models.User{},
&models.ViewRecord{},
&models.FeatureToggle{},
&models.BadgeViewCount{})
client, err := api.NewClient(api.Config{
@@ -74,8 +75,8 @@ func main() {
handler := &handlers.BadgesHandler{DB: db, PrometheusAPIClient: client}
userHandler := &handlers.UsersHandler{DB: db}
statsHandler := &handlers.StatsHandler{DB: db}
toggleHandler := &handlers.FeatureTogglesHandler{DB: db}
r := gin.Default()
@@ -97,6 +98,7 @@ func main() {
api.POST("/auth", userHandler.Authenticate)
api.POST("/badges", handler.CreateBadge)
api.GET("/badges", handler.MyBadges)
api.GET("/toggles", toggleHandler.Toggles)
statsAPI := r.Group("/api/stats")
statsAPI.Use(handler.ValidateBadge)
+5
View File
@@ -158,6 +158,11 @@ spec:
backend:
serviceName: badger-ui
servicePort: 80
- path: /badges
pathType: Exact
backend:
serviceName: badger-ui
servicePort: 80
- path: /stats
pathType: Prefix
backend:
+9
View File
@@ -0,0 +1,9 @@
package models
import "github.com/jinzhu/gorm"
type FeatureToggle struct {
gorm.Model
Name string `json:"name"`
Enabled bool `json:"enabled"`
}
+21 -22
View File
@@ -1,10 +1,10 @@
<template>
<b-overlay :show="isLoading" rounded="sm" variant="dark" class="overlay">
<b-navbar toggleable="md" type="dark" variant="dark">
<b-navbar-brand href="/" >Badges</b-navbar-brand>
<b-navbar-brand href="/">Badges</b-navbar-brand>
<b-navbar-toggle target="nav-collapse"> </b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav v-if="!isProduction">
<b-collapse id="nav-collapse" is-nav v-if="true">
<b-navbar-nav>
<b-nav-item to="/badges" exact>
My badges
@@ -43,25 +43,23 @@
<b-col md="3" class="contact-me">
<a href="mailto:me@toozhao.com" class="contact">Contact me</a>
</b-col>
<b-col md="3">
</b-col>
<b-col md="3"> </b-col>
</b-row>
<template #overlay>
<div class="text-center" v-if="hasError">
<b-icon icon="stopwatch" font-scale="3" animation="cylon"></b-icon>
<p id="error-detail">{{error}}</p>
<b-button
ref="cancel"
variant="outline-light"
size="sm"
aria-describedby="cancel-label"
href="/"
>
Back to homepage
</b-button>
</div>
</template>
<div class="text-center" v-if="hasError">
<!-- <b-icon icon="stopwatch" font-scale="3" animation="cylon"></b-icon> -->
<p id="error-detail">{{ error }}</p>
<b-button
ref="cancel"
variant="outline-light"
size="sm"
aria-describedby="cancel-label"
href="/"
>
Back to homepage
</b-button>
</div>
</template>
</b-overlay>
</template>
@@ -76,7 +74,7 @@ export default Vue.extend({
return;
}
this.$store.dispatch("users/loginFromLocal")
this.$store.dispatch("users/loginFromLocal");
if (this.$store.state.users.token === "") {
this.$store.dispatch("users/authenticate", {
@@ -98,7 +96,7 @@ export default Vue.extend({
hasError() {
return this.$store.state.error.error !== "";
},
error(){
error() {
return this.$store.state.error.error;
},
isProduction() {
@@ -142,7 +140,8 @@ html {
font-size: 13px;
background: #eee;
padding: 5vh 0;
.copyright, .contact-me {
.copyright,
.contact-me {
display: flex;
align-items: center;
justify-content: center;
+10 -3
View File
@@ -105,9 +105,9 @@ export default {
** See https://nuxtjs.org/api/configuration-build/
*/
build: {
babel: {
compact: true
}
// babel: {
// compact: true
// }
},
auth: {
redirect: {
@@ -145,6 +145,13 @@ export default {
port: 3000,
host: '0.0.0.0'
},
bootstrapVue: {
// Install the `IconsPlugin` plugin (in addition to `BootstrapVue` plugin)
icons: false,
components: ['BContainer', 'BRow', 'BCol', 'BFormInput', 'BButton', 'BTable', 'BModal', 'BCard',
'BLink', 'BCardText', 'BFormTextarea', 'BImg', 'BDropdownItem', 'BOverlay', 'BNavbar', 'BNavbarBrand',
'BNavbarToggle', 'BCollapse', 'BNavbarNav', 'BNavItem', 'BNavItemDropdown', 'BButtonGroup', 'BAlert']
}
// router: {
// middleware: ['auth']
// }
+59 -14
View File
@@ -3491,13 +3491,58 @@
}
},
"@nuxt/opencollective": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@nuxt/opencollective/-/opencollective-0.3.0.tgz",
"integrity": "sha512-Vf09BxCdj1iT2IRqVwX5snaY2WCTkvM0O4cWWSO1ThCFuc4if0Q/nNwAgCxRU0FeYHJ7DdyMUNSdswCLKlVqeg==",
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@nuxt/opencollective/-/opencollective-0.3.2.tgz",
"integrity": "sha512-XG7rUdXG9fcafu9KTDIYjJSkRO38EwjlKYIb5TQ/0WDbiTUTtUtgncMscKOYzfsY86kGs05pAuMOR+3Fi0aN3A==",
"requires": {
"chalk": "^2.4.2",
"consola": "^2.10.1",
"node-fetch": "^2.6.0"
"chalk": "^4.1.0",
"consola": "^2.15.0",
"node-fetch": "^2.6.1"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"@nuxt/server": {
@@ -6032,17 +6077,17 @@
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
},
"bootstrap": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.5.2.tgz",
"integrity": "sha512-vlGn0bcySYl/iV+BGA544JkkZP5LB3jsmkeKLFQakCOwCM3AOk7VkldBz4jrzSe+Z0Ezn99NVXa1o45cQY4R6A=="
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.0.tgz",
"integrity": "sha512-Io55IuQY3kydzHtbGvQya3H+KorS/M9rSNyfCGCg9WZ4pyT/lCxIlpJgG1GXW/PswzC84Tr2fBYi+7+jFVQQBw=="
},
"bootstrap-vue": {
"version": "2.16.0",
"resolved": "https://registry.npmjs.org/bootstrap-vue/-/bootstrap-vue-2.16.0.tgz",
"integrity": "sha512-gLETwPmeRHCe5WHmhGxzb5PtTEuKqQPGl0TFvZ2Odbkg/7UuIHdqIexrJRerpnomP4ZzDQ+qYGL91Ls9lcQsJQ==",
"version": "2.21.2",
"resolved": "https://registry.npmjs.org/bootstrap-vue/-/bootstrap-vue-2.21.2.tgz",
"integrity": "sha512-0Exe+4MZysqhZNXIKf4TzkvXaupxh9EHsoCRez0o5Dc0J7rlafayOEwql63qXv74CgZO8E4U8ugRNJko1vMvNw==",
"requires": {
"@nuxt/opencollective": "^0.3.0",
"bootstrap": ">=4.5.0 <5.0.0",
"@nuxt/opencollective": "^0.3.2",
"bootstrap": ">=4.5.3 <5.0.0",
"popper.js": "^1.16.1",
"portal-vue": "^2.1.7",
"vue-functional-data-merge": "^3.1.0"
+2 -2
View File
@@ -14,8 +14,8 @@
"@nuxtjs/auth-next": "5.0.0-1611574754.9020f2a",
"@nuxtjs/axios": "^5.12.5",
"@nuxtjs/pwa": "^3.0.0-beta.20",
"bootstrap": "^4.5.0",
"bootstrap-vue": "^2.15.0",
"bootstrap": "^4.6.0",
"bootstrap-vue": "^2.21.2",
"chart.js": "^2.9.4",
"cookie-parser": "^1.4.5",
"express-jwt": "^6.0.0",
+4 -1
View File
@@ -18,7 +18,7 @@
<b-card-text> </b-card-text>
<b-card-text>
<img :src="badgeUrl(badge)" class="my-badge" />
<b-link :href="statsUrl(badge)"><img :src="badgeUrl(badge)" class="my-badge" /></b-link>
</b-card-text>
<a href="#" class="card-link" style="display:none"><svg></svg></a>
@@ -62,6 +62,9 @@ export default {
},
badgeUrl(badge) {
return `${this.$config.backendURL}/badges/${badge.ulid}/green.svg?i=1`;
},
statsUrl(badge) {
return `/stats/${badge.ulid}`;
}
}
};
+2 -2
View File
@@ -8,14 +8,14 @@
<b-col md="4" class="text-center">
<b-card title="" bg-variant="light">
<div v-for="s in strategies" :key="s.key" class="mb-2">
<b-btn
<b-button
block
:style="{ background: s.color }"
class="login-button"
@click="$auth.loginWith(s.key)"
>
Login with {{ s.name }}
</b-btn>
</b-button>
</div>
</b-card>
</b-col>
+17
View File
@@ -0,0 +1,17 @@
export const state = () => ({
toggles: []
});
export const mutations = {
setToggles(state, toggles) {
state.toggles = toggles;
}
};
export const actions = {
async getToggles(context, callback) {
const result = await this.$axios.$get("/api/toggles");
context.commit("setToggles", result);
callback();
}
};