add stats

This commit is contained in:
2021-01-25 13:45:50 +11:00
parent 0574550c5a
commit 2871b71dbe
8 changed files with 3185 additions and 1400 deletions
+24 -10
View File
@@ -2,31 +2,45 @@ package handlers
import (
"net/http"
"time"
"github.com/getsentry/sentry-go"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
"github.com/sirupsen/logrus"
"github.com/wahyd4/badger/models"
)
type StatsHandler struct {
DB *gorm.DB
}
type StatsResult struct {
Date time.Time `json:"label"`
Count int `json:"data"`
}
func (handler *StatsHandler) GetStats(c *gin.Context) {
if err := handler.badgeStats(c); err != nil {
logrus.Error(err)
badge := c.MustGet("badge").(*models.Badge)
result, err := handler.badgeStats(badge)
if err != nil {
logrus.Errorf("failed to generate stats information for %s, %v", badge.ULID, err)
sentry.CaptureException(err)
if err == ErrNoSuchBadgeFound {
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": ErrorMessageInternalError})
return
}
c.JSON(200, gin.H{"msg": "hello"})
c.JSON(http.StatusOK, result)
}
func (handler *StatsHandler) badgeStats(c *gin.Context) error {
return nil
func (handler *StatsHandler) badgeStats(badge *models.Badge) ([]*StatsResult, error) {
var result = make([]*StatsResult, 0)
err := handler.DB.Raw(`select
date_trunc('day', created_at AT TIME ZONE 'Australia/Melbourne') as date, -- or hour, day, week, month, year
count(1)
from view_records
where ulid = ?
group by 1
order by date ASC`, badge.ULID).Scan(&result).Error
return result, err
}
+4 -2
View File
@@ -93,12 +93,14 @@ func main() {
api := r.Group("/api")
api.Use(userHandler.AuthRequired)
api.Group("/badges/:name", handler.ValidateBadge)
api.POST("/auth", userHandler.Authenticate)
api.POST("/badges", handler.CreateBadge)
api.GET("/badges", handler.MyBadges)
api.GET("/badges/:name/stats", statsHandler.GetStats)
statsAPI := r.Group("/api/stats")
statsAPI.Use(handler.ValidateBadge)
statsAPI.GET(":name", statsHandler.GetStats)
go func() {
http.Handle("/metrics", promhttp.Handler())
+20
View File
@@ -0,0 +1,20 @@
<script>
import { Line } from 'vue-chartjs'
export default {
extends: Line,
props: {
data: {
type: Object,
default: null
},
options: {
type: Object,
default: null
}
},
mounted () {
this.renderChart(this.data, this.options)
}
}
</script>
+2999 -1384
View File
File diff suppressed because it is too large Load Diff
+5 -3
View File
@@ -12,18 +12,20 @@
"dependencies": {
"@nuxt/typescript-runtime": "^1.0.0",
"@nuxtjs/auth-next": "5.0.0-1602966760.822bc05",
"@nuxtjs/axios": "^5.12.2",
"@nuxtjs/axios": "^5.12.5",
"@nuxtjs/pwa": "^3.0.0-beta.20",
"bootstrap": "^4.5.0",
"bootstrap-vue": "^2.15.0",
"chart.js": "^2.9.4",
"cookie-parser": "^1.4.5",
"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"
"nuxt": "^2.14.12",
"nuxt-i18n": "^6.13.12",
"vue-chartjs": "^3.5.1"
},
"devDependencies": {
"@nuxt/types": "^2.14.4",
+2 -1
View File
@@ -205,7 +205,8 @@ export default Vue.extend({
},
updateBadgeText: function(color) {
var url = `${this.$config.backendURL}/badges/${this.badge.id}/${color}.svg`;
this.text = `[![Page Views Count](${url})](${url} "Get your own page views count badge on badges.toozhao.com")`;
var statsUrl = `${this.$config.backendURL}/stats/${this.badge.id}`;
this.text = `[![Page Views Count](${url})](${statsUrl} "Get your own page views count badge on badges.toozhao.com")`;
this.activeBadgeColor = color;
},
myBadge: function(color) {
+113
View File
@@ -0,0 +1,113 @@
<template>
<div class="stats-container container">
<b-container fluid="lg">
<b-row>
<b-col lg="12">
<h3>Badge view count statistics</h3>
<img :src="badgeUrl(id)" class="my-badge" />
</b-col>
</b-row>
<b-row class="stats">
<b-col lg="12">
<line-chart :data="chartsData" :options="options" v-if="loaded" />
</b-col>
</b-row>
<b-row class="">
<b-col lg="4" offset-lg="4" class="text-center generate-badge">
<b-button
pill
size="lg"
class="generate-button"
variant="outline-primary"
href="/"
>Create another Badge
</b-button>
</b-col>
</b-row>
</b-container>
</div>
</template>
<script>
import { mapMutations, mapActions } from "vuex";
import moment from "moment";
export default {
data: () => ({
loaded: false,
chartData: null
}),
props: {
options: {
type: Object,
default: () => {
return {
legend: {
display: true,
position: 'bottom',
align: 'end'
},
scales: {
yAxes: [{
stacked: true,
backgroundColor: 'rgba(0, 0, 0, 0.9)',
}]
},
responsive: true,
maintainAspectRatio: false
};
}
}
},
computed: {
id() {
return this.$route.params.id;
},
stats() {
return this.$store.state.stats;
}
},
mounted() {
this.loaded = false;
this.$store.commit("loading/updateLoading");
this.$store.dispatch("stats/getBadgeStats", {
badgeId: this.$route.params.id,
callback: result => {
const labels = result.map(item => moment(item.label).format("MM-DD"));
const data = result.map(item => item.data);
this.chartsData = {
labels: labels,
datasets: [
{
label: "View Count",
data: data,
borderWidth: 2,
borderColor: 'rgb(49, 197, 83)',
fill: false,
lineTension: 1
}
]
};
this.$store.commit("loading/updateLoading");
this.loaded = true;
}
});
},
methods: {
badgeUrl(id) {
return `${this.$config.backendURL}/badges/${id}/green.svg?i=1`;
},
badgeCreated(createdAt) {
return `Created at: ${moment(createdAt).format("MM-DD ")}`;
}
}
};
</script>
<style lang="scss">
.stats-container {
margin-top: 5rem;
.stats {
margin-top: 2rem;
}
}
</style>
+18
View File
@@ -0,0 +1,18 @@
export const state = () => ({
stats: []
});
export const mutations = {
setStats(state, stats) {
state.stats = stats;
}
};
export const actions = {
async getBadgeStats(context, {badgeId, callback}) {
const result = await this.$axios.$get(`/api/stats/${badgeId}`);
context.commit("setStats", result);
callback(result);
}
};