Compare commits

...

21 Commits
v1.3 ... master

Author SHA1 Message Date
kolaente f944661111
Fixed lint
continuous-integration/drone/push Build is passing Details
2019-09-15 16:06:49 +02:00
kolaente 20836970e5
Swapped rows
continuous-integration/drone/push Build is failing Details
2019-09-14 20:33:29 +02:00
kolaente e4bca43489
Dark theme all the things 2019-09-14 20:18:32 +02:00
kolaente cdab64428d
Vue min 2019-09-14 19:29:33 +02:00
kolaente 6c7202658e
Dark mode 2019-09-14 19:22:39 +02:00
kolaente e66bd64a07
Added Metrics 2019-09-14 19:15:41 +02:00
kolaente 6cd54f7005
Added frontend background
continuous-integration/drone/push Build is passing Details
2019-09-14 17:36:26 +02:00
kolaente 6e2a468b22
More number formatting 2019-09-14 17:29:09 +02:00
kolaente d0cb590e04
Number formatting 2019-09-14 17:23:42 +02:00
kolaente f7eb4f9ca8
Fixed adding new stuff
continuous-integration/drone/push Build is passing Details
2019-09-14 17:21:48 +02:00
kolaente 59420922a5
Show places
continuous-integration/drone/push Build is passing Details
2019-09-14 17:15:47 +02:00
kolaente 25e9ac4982
Highlight active row 2019-09-14 17:14:43 +02:00
kolaente 916597dff6
Highlight active row
continuous-integration/drone/push Build is passing Details
2019-09-14 17:13:51 +02:00
kolaente 0b4083e611
Vue JS all the things
continuous-integration/drone/push Build is passing Details
2019-09-14 17:08:22 +02:00
kolaente b89c5bc17d
tabbing is now a thing
continuous-integration/drone/push Build is passing Details
2019-09-11 20:15:44 +02:00
kolaente 3c8a74f203
Re-enabled alphabetic sort order in admin 2019-09-11 19:32:24 +02:00
kolaente 747b169374
Disabled sql query log 2019-09-11 19:22:22 +02:00
kolaente 7f0d1f2ea1
Fixed a bug where it was not possible to reset coins 2019-09-11 19:22:04 +02:00
kolaente ac64aa2539
Added config.ini to gitignore
continuous-integration/drone/push Build is passing Details
2019-09-11 17:36:22 +02:00
kolaente 4fabf3f945
Re-added semantic assets
continuous-integration/drone/push Build is passing Details
2019-09-11 17:35:17 +02:00
kolaente 4aa9229a09
Added update with enter
continuous-integration/drone/push Build is passing Details
2019-09-11 17:25:03 +02:00
27 changed files with 2925 additions and 164 deletions

1
.gitignore vendored
View File

@ -7,3 +7,4 @@ output/
Konfi-Castle-Kasino
bind_linux_amd64.go
dist/
config.ini

BIN
assets/bg_frontend.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 KiB

4
assets/css/admin.css Normal file
View File

@ -0,0 +1,4 @@
body{
background:#121212;
color: #fff;
}

4
assets/css/frontend.css Normal file
View File

@ -0,0 +1,4 @@
body {
background: url('/assets/bg_frontend.jpg') fixed no-repeat center;
background-size: cover;
}

View File

@ -1,23 +0,0 @@
body{
background:#fff;
font-family:sans-serif;
}
th,td{
border: 1px solid #ccc;
border-bottom: none;
border-right: none;
padding: 2px 5px;
}
tr.top th{
border: none;
text-align: left;
padding-left: 10px;
}
table{
border:1px solid #ccc;
border-left: none;
border-top: none;
}

View File

@ -1,117 +1,164 @@
function getList() {
$.getJSON('/list?asc=asc', function (data) {
$("#list").html('');
$.each(data, function (i, item) {
// Modus nach Gemeindeb
if(item.gemeinde !== undefined) {
$("#list").append('<tr id="kcoins_row_' + item.id + '">' +
'<td>' + item.name + '</td> ' +
'<td>' + item.gemeinde + '</td> ' +
'<td id="kcoins_display_' + item.id + '">' + item.kcoins + '</td>' +
'<td><span class="ui action input" id="kcoins_container_' + item.id + '"><input type="number" value="0" id="kcoins_' + item.id + '" name="kcoins" autocomplete="off" /><button class="ui right labeled icon button green" onclick="updateCoins(\'' + item.id + '\');"><i class="right dollar icon"></i>KonfiCoins Hinzufügen</button></span>&nbsp;&nbsp;&nbsp;&nbsp;<button class="ui button red" onclick="deleteKonfi(\'' + item.id + '\');" id="kcoins_container_' + item.id + '">Konfi Löschen</button></td></tr>');
} else {
$("#list").append('<tr id="kcoins_row_' + item.id + '"> ' +
'<td>' + item.name + '</td> ' +
'<td id="kcoins_display_' + item.id + '">' + item.kcoins + '</td>' +
'<td>' + item.konfi_count + '</td> ' +
'<td id="kcoins_quota_' + item.id + '">' + (item.coins_quota).toFixed(2) + '</td> ' +
'<td><span class="ui action input" id="kcoins_container_' + item.id + '"><input type="number" value="0" id="kcoins_' + item.id + '" name="kcoins" autocomplete="off" /><button class="ui right labeled icon button green" onclick="updateCoins(\'' + item.id + '\');"><i class="right dollar icon"></i>KonfiCoins Hinzufügen</button></span>&nbsp;&nbsp;&nbsp;&nbsp;<button class="ui button red" onclick="deleteGemeinde(\'' + item.id + '\');" id="kcoins_container_' + item.id + '">Gemeinde Löschen</button></td></tr>');
const app = new Vue({
el: '#adminedit',
template: `
<div>
<div id="msg" v-if="error !== ''"> {{ error }}</div>
<table class="ui celled striped inverted table">
<thead>
<tr>
<th>Name</th>
<td v-if="mode === 0">Gemeinde</td>
<th>KonfiCoins</th>
<th v-if="mode === 1">Konfis</th>
<th v-if="mode === 1">Konficoins pro Person</th>
<th>Bearbeiten</th>
</tr>
</thead>
<tbody id="list">
<tr v-if="data.length === 0">
<td colspan="5">Laden...</td>
</tr>
<tr v-for="(item, i) in data" :class="{ active: currentRow === item.id }">
<td>{{ item.name }}</td>
<td v-if="mode === 0">{{ item.gemeinde }}</td>
<td>{{ item.kcoins.toLocaleString('de-DE') }}</td>
<td v-if="mode === 1">{{ item.konfi_count }}</td>
<td v-if="mode === 1">{{ parseFloat((item.coins_quota).toFixed(2)).toLocaleString('de-DE') }}</td>
<td>
<span class="ui action input">
<input type="number" :tabindex="(i +1)" @focus="currentRow = item.id" @keyup.enter="updateCoins(item.id)" autocomplete="off" v-model="formStuff[item.id].addCoins"/>
<a class="ui right labeled icon button green" @click="updateCoins(item.id)">
<i class="right dollar icon"></i>
KonfiCoins Hinzufügen
</a>
</span>
&nbsp;&nbsp;&nbsp;&nbsp;
<a v-if="!formStuff[item.id].showDelete" class="ui button red" @click="formStuff[item.id].showDelete = true">
Löschen
</a>
<span v-if="formStuff[item.id].showDelete">
Sicher?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<a class="ui button red" @click="deleteStuff(item.id)">
Löschen
</a>
<a class="ui button" @click="formStuff[item.id].showDelete = false">
Abbrechen
</a>
</span>
</td>
</tr>
</tbody>
</table>
</div>`,
data() {
return {
mode: 1,
data: [],
error: '',
addCoins: 0,
loading: false,
formStuff: {},
currentRow: 0,
}
},
beforeMount() {
this.mode = mode
},
mounted() {
if (typeof (EventSource) === "undefined") {
this.error = 'Diese Browser wird nicht unterstützt.'
return
}
let source = new EventSource('/events');
source.onmessage = e => {
console.debug('unsupported event!', e)
};
source.addEventListener('init', e => {
this.data = JSON.parse(e.data)
for (const i in this.data) {
this.$set(this.formStuff, this.data[i].id, {addCoins: 0, showDelete: false})
}
});
});
}
getList();
function updateCoins(id) {
let addcoins = $('#kcoins_' + id).val();
if(addcoins !== 0) {
$('#coins_container_' + id).addClass('disabled');
$.ajax({
url: '/admin/update',
method: 'POST',
data: 'id=' + id + '&addcoins=' + addcoins,
success: function (msg) {
$('#coins_container_' + id).removeClass('disabled');
if (msg.message === 'success') {
$('#kcoins_' + id).val("0");
$('#kcoins_display_' + id).html(msg.data.kcoins);
if(msg.data.coins_quota !== undefined) {
$('#kcoins_quota_' + id).html(msg.data.coins_quota.toFixed(2));
}
} else {
$('#msg').html('<div class="ui error message" style="display: block;">Ein Fehler trat auf.</div>');
this.sortData()
})
source.addEventListener('update', e => {
this.update(JSON.parse(e.data))
})
source.addEventListener('create', e => {
this.create(JSON.parse(e.data))
})
source.addEventListener('delete', e => {
this.delete(JSON.parse(e.data))
})
},
methods: {
sortData() {
this.data.sort((a, b) => {
return a.name < b.name ? -1 : 1
})
},
update(updatedData) {
for (const i in this.data) {
if (this.data[i].id === updatedData.id) {
this.$set(this.data, i, updatedData)
}
}
});
}
}
function deleteKonfi(id) {
$('#kcoins_container_' + id).addClass('disabled');
$('.ui.basic.kofidel.modal')
.modal({
closable : false,
duration: 200,
onDeny : function(){
$('#kcoins_container_' + id).removeClass('disabled');
return true;
},
onApprove : function() {
$.ajax({
url: '/admin/delete',
method: 'POST',
data: 'id=' + id,
success: function (msg) {
if (msg === 'success') {
getList();
$('#msg').html('<div class="ui success message" style="display: block;">Der Konfi wurde erfolgreich gelöscht.</div>');
} else {
$('#msg').html('<div class="ui error message" style="display: block;">Ein Fehler trat auf.</div>');
}
}
});
this.sortData()
},
create(createdData) {
this.data.push(createdData)
this.$set(this.formStuff, createdData.id, {addCoins: 0, showDelete: false})
this.sortData()
},
delete(deletedData) {
for (const i in this.data) {
if (this.data[i].id === deletedData.id) {
this.data.splice(i, 1)
}
}
})
.modal('show')
;
}
this.sortData()
},
updateCoins(id) {
this.loading = true
function deleteGemeinde(id) {
$('#kcoins_container_' + id).addClass('disabled');
$('.ui.basic.gemeindedel.modal')
.modal({
closable : false,
duration: 200,
onDeny : function(){
$('#kcoins_container_' + id).removeClass('disabled');
return true;
},
onApprove : function() {
$.ajax({
url: '/admin/delete',
method: 'POST',
data: 'id=' + id,
success: function (msg) {
if (msg === 'success') {
getList();
$('#msg').html('<div class="ui success message" style="display: block;">Die Gemeinde wurde erfolgreich gelöscht.</div>');
} else {
$('#msg').html('<div class="ui error message" style="display: block;">Ein Fehler trat auf.</div>');
}
}
});
if (this.formStuff[id].addCoins == 0) {
return
}
})
.modal('show')
;
}
let formData = new FormData();
formData.append('id', id);
formData.append('addcoins', this.formStuff[id].addCoins);
fetch('/admin/update', {
method: 'POST',
body: formData
})
.catch(e => {
this.error = e
})
.finally(() => {
this.loading = false
this.$set(this.formStuff, id, {addCoins: 0, showDelete: false})
})
},
deleteStuff(id) {
this.loading = true
let formData = new FormData();
formData.append('id', id);
fetch('/admin/delete', {
method: 'POST',
body: formData
})
.catch(e => {
this.error = e
})
.finally(() => {
this.loading = false
})
},
},
});
// Konfi hinzufügen
$('.ui.kofiadd.modal')
@ -155,8 +202,6 @@ $('.ui.gemeindeadd.modal')
$('.loader').removeClass('active');
if (msg === 'success') {
$('#name').val('');
getList();
$('#msg').html('<div class="ui success message" style="display: block;">Die Gemeinde wurde erfolgreich hinzugefügt.</div>');
} else {
$('#msg').html('<div class="ui error message" style="display: block;">Ein Fehler trat auf.</div>');

View File

@ -3,25 +3,27 @@ const app = new Vue({
template: `
<div style="width: 99%; margin: 0 auto;padding-top: 10px;">
<div class="ui error message" style="display: block;" v-if="error !== ''">{{ error }}</div>
<table class="ui celled table" v-if="error === ''">
<table class="ui celled striped inverted table" v-if="error === ''">
<thead>
<tr class="top">
<th scope="col">Platz</th>
<th scope="col" v-if="mode === 0">Name</th>
<th scope="col" v-if="mode === 1">Gemeinde</th>
<th scope="col" v-if="mode === 0">Gemeinde</th>
<th scope="col" v-if="mode === 1">KonfiCoins pro Person</th>
<th scope="col">Eingezahlte KonfiCoins Gesamt</th>
<th scope="col" v-if="mode === 1">KonfiCoins p.P.</th>
</tr>
</thead>
<tbody>
<tr v-if="data.length === 0">
<td colspan="4">Laden...</td>
</tr>
<tr v-for="item in data">
<tr v-for="(item, i) in data">
<td>{{ (i + 1) }}.</td>
<td>{{ item.name }}</td>
<td v-if="mode === 0">{{ item.gemeinde }}</td>
<td>{{ item.kcoins }}</td>
<td v-if="mode === 1">{{ (item.coins_quota).toFixed(2) }}</td>
<td v-if="mode === 1">{{ parseFloat((item.coins_quota).toFixed(2)).toLocaleString('de-DE') }}</td>
<td>{{ item.kcoins.toLocaleString('de-DE') }}</td>
</tr>
</tbody>
</table>

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -11,5 +11,8 @@ Interface = :8080
; Hier wird die Datenbank gespeichert
DBFile = ./data.db
; Ob Fenster geöffnet werden sollen, oder nicht.
OpenWindows = true
OpenBrowser = false
OpenWindows = false
OpenBrowser = false
; Metrics
SaveMetrics = true

View File

@ -12,4 +12,7 @@ Interface = 127.0.0.1:8080
DBFile = ./data.db
; Ob Fenster geöffnet werden sollen, oder nicht.
OpenWindows = true
OpenBrowser = false
OpenBrowser = false
; Metrics
SaveMetrics = false

10
main.go
View File

@ -53,6 +53,16 @@ func main() {
}
}()
if config.GetSaveMetrics() {
log.Info("Saving Metrics.")
go func() {
for {
models.AddMetric()
time.Sleep(60 * time.Second)
}
}()
}
// Windows
if config.GetOpenWindows() {
go windows.OpenWindows()

View File

@ -13,6 +13,7 @@ type Configuration struct {
Mode int
OpenWindows bool
OpenBrowser bool
SaveMetrics bool
}
var siteConf = &Configuration{}
@ -59,3 +60,8 @@ func GetOpenWindows() bool {
func GetOpenBrowser() bool {
return siteConf.OpenBrowser
}
// GetSaveMetrics returns whether to use metrics or not
func GetSaveMetrics() bool {
return siteConf.SaveMetrics
}

View File

@ -62,7 +62,10 @@ func (c *Community) Update(moreCoins int64) (err error) {
c.KCoins += moreCoins
// Update
_, err = x.Where("id = ?", c.ID).Update(c)
_, err = x.
Cols("k_coins").
Where("id = ?", c.ID).
Update(c)
if err != nil {
return
}

View File

@ -22,7 +22,7 @@ func DBinit() {
x.ShowSQL(false)
x.Logger().SetLevel(core.LOG_DEBUG)
x.Sync(&Kofi{}, &Community{})
x.Sync(&Kofi{}, &Community{}, &Metric{})
return
}

View File

@ -34,7 +34,10 @@ func (k *Kofi) Update(moreCoins int64) (err error) {
k.KCoins += moreCoins
// Update
_, err = x.Where("id = ?", k.ID).Update(k)
_, err = x.
Cols("k_coins").
Where("id = ?", k.ID).
Update(k)
return
}

31
pkg/models/metric.go Normal file
View File

@ -0,0 +1,31 @@
package models
import "github.com/labstack/gommon/log"
// Metric is the structure for metrics
type Metric struct {
ID int64 `xorm:"pk autoincr" json:"id" form:"id"`
Kcoins int64 `xorm:"bigint(11)"`
CommunityID int64 `xorm:"bigint(11)"`
CreatedUnix int64 `xorm:"created"`
}
// AddMetric saves a new metric point
func AddMetric() {
allCommunites := []Community{}
err := x.Find(&allCommunites)
if err != nil {
log.Error("Error getting metric data", err)
}
for _, community := range allCommunites {
m := Metric{
Kcoins: community.KCoins,
CommunityID: community.ID,
}
_, err := x.Insert(m)
if err != nil {
log.Error("Error saving metrics", err)
}
}
}

View File

@ -24,7 +24,11 @@ func isLoggedIn(c echo.Context) bool {
}
func adminHandler(c echo.Context) error {
adminInfos := AdminInfos{true, config.GetMode(), models.Version}
adminInfos := AdminInfos{
Loggedin: true,
Mode: config.GetMode(),
Version: models.Version,
}
if isLoggedIn(c) {
return c.Render(http.StatusOK, "admin_mode_"+strconv.Itoa(config.GetMode()), adminInfos)
}

View File

@ -1,4 +1,9 @@
{{define "admin_footer"}}
<script>
const mode = {{.Mode}}
</script>
<script src="/assets/js/vue.min.js"></script>
<script src="/assets/js/admin.js"></script>
</body>

View File

@ -5,6 +5,7 @@
<meta charset="UTF-8">
<title>Kasino Admin</title>
<link rel="stylesheet" type="text/css" href="/assets/semantic/semantic.min.css">
<link rel="stylesheet" type="text/css" href="/assets/css/admin.css">
<script>if (typeof module === 'object') {
window.module = module;

View File

@ -10,23 +10,10 @@
</a>
</p>
<div id="msg"></div>
<table width="100%" border="0" cellpadding="0" cellspacing="0" class="ui celled table">
<thead>
<tr>
<th>Name</th>
<th>KonfiCoins</th>
<th>Konfis</th>
<th>KonfiCoins p.P.</th>
<th>Bearbeiten</th>
</tr>
</thead>
<tbody id="list">
<tr>
<td colspan="5">Laden...</td>
</tr>
</tbody>
</table>
<div id="adminedit">
</div>
<p style="color: #ccc;">© 2017-2019 <a href="http://konradlangenberg.de" target="_blank" style="color:#ccc;">Konrad
Langenberg</a> | Version: {{.Version}}</p>
</div>
@ -79,6 +66,6 @@
</div>
</div>
{{template "admin_footer"}}
{{template "admin_footer" .}}
{{end}}
{{end}}

View File

@ -4,7 +4,8 @@
<head>
<meta charset="UTF-8">
<title>Kasino</title>
<link rel="stylesheet" type="text/css" href="/assets/semantic/semantic.min.css">
<link rel="stylesheet" type="text/css" href="/assets/semantic/semantic.min.css"/>
<link rel="stylesheet" type="text/css" href="/assets/css/frontend.css" />
</head>
<body>
<div id="table"></div>