WIP
This commit is contained in:
parent
d0b1c1d241
commit
00cca5ca9a
@ -58,6 +58,8 @@ fun Payload.mid() = getClaim("id").asInt()
|
|||||||
|
|
||||||
|
|
||||||
object Security {
|
object Security {
|
||||||
|
fun DEFAULT_EXPIRY() = Date(System.currentTimeMillis() + 1000*60*60);
|
||||||
|
|
||||||
suspend fun authenticateUser(application: Application, username: String, password: String): Ministrant? {
|
suspend fun authenticateUser(application: Application, username: String, password: String): Ministrant? {
|
||||||
if(username == "admin") {
|
if(username == "admin") {
|
||||||
val adminPw = application.environment.config.property("admin.password").getString()
|
val adminPw = application.environment.config.property("admin.password").getString()
|
||||||
@ -97,6 +99,6 @@ object Security {
|
|||||||
.withIssuer(jwtEnv.issuer)
|
.withIssuer(jwtEnv.issuer)
|
||||||
.withClaim("username", ministrant.username)
|
.withClaim("username", ministrant.username)
|
||||||
.withClaim("id", ministrant.id)
|
.withClaim("id", ministrant.id)
|
||||||
.withExpiresAt(Date(System.currentTimeMillis() + 1000*60*60))
|
.withExpiresAt(DEFAULT_EXPIRY())
|
||||||
.sign(Algorithm.HMAC256(jwtEnv.secret))
|
.sign(Algorithm.HMAC256(jwtEnv.secret))
|
||||||
}
|
}
|
||||||
@ -28,7 +28,7 @@ data class AuthenticationRequest(
|
|||||||
@Serializable
|
@Serializable
|
||||||
data class AuthenticationResult(
|
data class AuthenticationResult(
|
||||||
val success: Boolean,
|
val success: Boolean,
|
||||||
val token: String? = null
|
val privileges: List<String>? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -54,8 +54,14 @@ fun Route.configureAuthenticationRoutes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val token = Security.createToken(jwtEnv, ministrant)
|
val token = Security.createToken(jwtEnv, ministrant)
|
||||||
|
val expiry = Security.DEFAULT_EXPIRY().toGMTString()
|
||||||
|
|
||||||
call.respond(AuthenticationResult(true, token.toString()))
|
call.response.header(
|
||||||
|
"Set-Cookie",
|
||||||
|
"token=$token; HttpOnly; Expires=$expiry"
|
||||||
|
)
|
||||||
|
|
||||||
|
call.respond(AuthenticationResult(true, ministrant.privileges))
|
||||||
}
|
}
|
||||||
|
|
||||||
authenticate {
|
authenticate {
|
||||||
@ -80,6 +86,7 @@ fun Route.configureAuthenticationRoutes() {
|
|||||||
|
|
||||||
Security.setPassword(request.username, newPassword)
|
Security.setPassword(request.username, newPassword)
|
||||||
|
|
||||||
|
|
||||||
call.respond(hashMapOf("password" to newPassword))
|
call.respond(hashMapOf("password" to newPassword))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,22 +1,72 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { RouterLink, RouterView } from 'vue-router'
|
import {RouterLink, RouterView} from 'vue-router'
|
||||||
import HelloWorld from './components/HelloWorld.vue'
|
import HelloWorld from './components/HelloWorld.vue'
|
||||||
|
import LoginPanel from "@/components/LoginPanel.vue";
|
||||||
|
import {ref} from "vue";
|
||||||
|
|
||||||
|
const showPopup = ref(false)
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<header>
|
<nav>
|
||||||
Miniplan
|
<div class="left">
|
||||||
</header>
|
Miniplan
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<button class="flat" @click="showPopup = true"><i>login</i> Einloggen</button>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
<RouterView />
|
<RouterView/>
|
||||||
|
<div class="popup-container" :class="{show: showPopup}" @click.self="showPopup = false">
|
||||||
|
<LoginPanel :active="showPopup"/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
header{
|
nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 20px 32px;
|
align-items: center;
|
||||||
|
padding: 10px 32px;
|
||||||
border-bottom: 1px solid #d7d5d5;
|
border-bottom: 1px solid #d7d5d5;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 100;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
transition: 200ms opacity;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
* {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.show{
|
||||||
|
pointer-events: auto;
|
||||||
|
* {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -26,17 +26,23 @@ html, body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
border: none;
|
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 8px 14px 8px 10px;
|
padding: 8px 14px 8px 10px;
|
||||||
margin: 0 4px;
|
margin: 0 4px;
|
||||||
border-radius: 4px;
|
border-radius: 6px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
background: #d7eaf3;
|
background: #d7eaf3;
|
||||||
color: #0e2c48;
|
color: #0e2c48;
|
||||||
|
border: 1px solid #bed4e0;
|
||||||
|
transition: 100ms border-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.flat {
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
button i {
|
button i {
|
||||||
@ -45,10 +51,14 @@ button i {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
button:hover {
|
button.flat:hover{
|
||||||
|
border-color: #e5e5e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:not(.flat):hover {
|
||||||
background: #e4eff6;
|
background: #e4eff6;
|
||||||
}
|
}
|
||||||
|
|
||||||
button:active {
|
button:not(.flat):active {
|
||||||
background: #d0e3f1;
|
background: #d0e3f1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import {ref} from "vue";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
value: any,
|
value: any,
|
||||||
label?: string,
|
label?: string,
|
||||||
@ -8,44 +10,71 @@ const props = defineProps<{
|
|||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits(["update:value"])
|
const emit = defineEmits(["update:value"])
|
||||||
|
const focus = ref(false)
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<label v-if="label">{{ label }}</label>
|
<label v-if="label" :class="{up: props.value != '' || focus, focus}">{{ label }}</label>
|
||||||
<input
|
<input
|
||||||
:value="value"
|
:value="value"
|
||||||
@input="$emit('update:value', $event.target.value)"
|
@input="$emit('update:value', $event.target.value)"
|
||||||
:type="props.type ? props.type : 'text'"
|
:type="props.type ? props.type : 'text'"
|
||||||
:disabled="disabled">
|
:disabled="disabled"
|
||||||
|
@focusin="focus = true"
|
||||||
|
@focusout="focus = false">
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
label {
|
position: relative;
|
||||||
display: block;
|
|
||||||
padding-left: 15px;
|
label {
|
||||||
font-size: 14px;
|
display: block;
|
||||||
color: #727272;
|
font-size: 14px;
|
||||||
}
|
padding: 2px 4px;
|
||||||
input {
|
color: #727272;
|
||||||
font-family: sans-serif;
|
position: absolute;
|
||||||
width: calc(100% - 30px);
|
top: 12px;
|
||||||
min-width: 0px;
|
left: 10px;
|
||||||
outline: none;
|
z-index: 1;
|
||||||
margin: 0 10px;
|
background: #ffffff;
|
||||||
padding: 5px 5px;
|
pointer-events: none;
|
||||||
color: #121212;
|
transition: 100ms top;
|
||||||
border: 1px solid transparent;
|
&.up {
|
||||||
font-size: 14px;
|
top: -8px;
|
||||||
&:not(:disabled){
|
font-size: 12px;
|
||||||
border: 1px solid #cecece;
|
}
|
||||||
|
&.focus {
|
||||||
|
color: #464646;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
position: relative;
|
||||||
|
font-family: sans-serif;
|
||||||
|
width: calc(100% - 30px);
|
||||||
|
min-width: 0px;
|
||||||
|
outline: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 15px 15px;
|
||||||
|
color: #121212;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: 100ms border-color;
|
||||||
|
|
||||||
|
&:not(:disabled) {
|
||||||
|
border: 1px solid #cecece;
|
||||||
|
&:focus{
|
||||||
|
border-color: #919191;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@ -1,11 +1,70 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import Input from "@/components/Input.vue";
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import {API} from "@/views/api";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
active: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits(["success"])
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener("keydown", ev => {
|
||||||
|
if(props.active && ev.key == "Enter") {
|
||||||
|
attemptLogin()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const username = ref("")
|
||||||
|
const password = ref("")
|
||||||
|
|
||||||
|
async function attemptLogin() {
|
||||||
|
let login = await API.login(username.value, password.value)
|
||||||
|
if(login.success){
|
||||||
|
console.log("success", login)
|
||||||
|
emit("success", login)
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<span class="title">Anmelden</span>
|
||||||
|
<Input class="input" v-model:value="username" label="Nutzername"/>
|
||||||
|
<Input class="input" v-model:value="password" label="Passwort" type="password"/>
|
||||||
|
<button><i>login</i>Anmelden</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
|
||||||
|
.container{
|
||||||
|
background: #ffffff;
|
||||||
|
padding: 20px 32px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
pointer-events: auto;
|
||||||
|
|
||||||
|
.title{
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
button{
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -125,6 +125,7 @@ function toggleMark(gid, mid) {
|
|||||||
<tr>
|
<tr>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th v-for="godi in props.gottesdienste">{{ formatWeekday(godi.date) }}</th>
|
<th v-for="godi in props.gottesdienste">{{ formatWeekday(godi.date) }}</th>
|
||||||
|
<th class="edit" v-if="props.edit"></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</thead>
|
</thead>
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
const emit = defineEmits(["addPlan", "save"])
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
save: boolean,
|
save: boolean,
|
||||||
plan: boolean,
|
plan: boolean,
|
||||||
@ -10,8 +11,7 @@ const props = defineProps<{
|
|||||||
|
|
||||||
<div class="action-bar" :class="{save: props.save}">
|
<div class="action-bar" :class="{save: props.save}">
|
||||||
<div class="other-action">
|
<div class="other-action">
|
||||||
<button class="add-plan" :class="{show: props.plan}" @click="$emit('save')"> <i class="icon">add_box</i> Neuer Plan</button>
|
<button class="add-plan" :class="{show: props.plan}" @click="$emit('addPlan')"> <i class="icon">add_box</i> Neuer Plan</button>
|
||||||
<button class="add-godi" :class="{show: props.godi}" @click="$emit('save')"> <i class="icon">add</i> Neuer Gottesdienst</button>
|
|
||||||
</div>
|
</div>
|
||||||
<button class="save" :class="{show: props.save}" @click="$emit('save')"><i class="icon">save</i> Änderungen speichern </button>
|
<button class="save" :class="{show: props.save}" @click="$emit('save')"><i class="icon">save</i> Änderungen speichern </button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -3,10 +3,32 @@
|
|||||||
import {API} from "@/views/api";
|
import {API} from "@/views/api";
|
||||||
|
|
||||||
import {onMounted, reactive, ref} from "vue";
|
import {onMounted, reactive, ref} from "vue";
|
||||||
import type {PlanModel, SimplifiedMinistrant} from "@/models/models";
|
import type {Gottesdienst, Mark, PlanModel, SimplifiedMinistrant} from "@/models/models";
|
||||||
|
import Input from "@/components/Input.vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
gottesdienste: Gottesdienst[],
|
||||||
|
ministranten: SimplifiedMinistrant[]
|
||||||
|
marks: Mark[],
|
||||||
|
editable: number[]
|
||||||
|
edit: boolean
|
||||||
|
}>()
|
||||||
|
const emit = defineEmits(["toggleMark", "added", "delete", "endEdit"])
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
godi: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener("keypress", ev => {
|
||||||
|
if(ev.key == "Enter" && props.edit){
|
||||||
|
emit("added", data.godi, () => {
|
||||||
|
data.godi = {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
const props = defineProps<PlanModel>()
|
|
||||||
defineEmits(["toggleMark"])
|
|
||||||
|
|
||||||
function getIconForMark(gid, mid) {
|
function getIconForMark(gid, mid) {
|
||||||
const mark = getMark(gid, mid).value
|
const mark = getMark(gid, mid).value
|
||||||
@ -100,25 +122,36 @@ function getMinistrantClasses(mini: SimplifiedMinistrant) {
|
|||||||
|
|
||||||
<thead>
|
<thead>
|
||||||
|
|
||||||
|
<tr v-if="props.edit">
|
||||||
|
<th></th>
|
||||||
|
<th v-for="godi in props.gottesdienste"><i @click="$emit('delete', godi.id)">delete</i></th>
|
||||||
|
<th><i @click="$emit('endEdit')">close</i></th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th v-for="godi in props.gottesdienste">{{ godi.name }}</th>
|
<th v-for="godi in props.gottesdienste">{{ godi.name }}</th>
|
||||||
|
<th class="edit" v-if="props.edit"><Input v-model:value="data.godi.name"/></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="bold">
|
<tr class="bold">
|
||||||
<th>Datum</th>
|
<th>Datum</th>
|
||||||
<th v-for="godi in props.gottesdienste">{{ formatDay(godi.date) }}</th>
|
<th v-for="godi in props.gottesdienste">{{ formatDay(godi.date) }}</th>
|
||||||
|
<th class="edit" v-if="props.edit"><Input v-model:value="data.godi.date" type="date"/></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Uhrzeit</th>
|
<th>Uhrzeit</th>
|
||||||
<th v-for="godi in props.gottesdienste">{{ formatTime(godi.date) }}</th>
|
<th v-for="godi in props.gottesdienste">{{ formatTime(godi.date) }}</th>
|
||||||
|
<th class="edit" v-if="props.edit"><Input v-model:value="data.godi.time" type="time"/></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="bold">
|
<tr class="bold">
|
||||||
<th>Anwesenheit</th>
|
<th>Anwesenheit</th>
|
||||||
<th v-for="godi in props.gottesdienste">{{ formatTime(godi.attendance) }}</th>
|
<th v-for="godi in props.gottesdienste">{{ formatTime(godi.attendance) }}</th>
|
||||||
|
<th class="edit" v-if="props.edit"><Input v-model:value="data.godi.attendance" type="time"/></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Wochentag</th>
|
<th>Wochentag</th>
|
||||||
<th v-for="godi in props.gottesdienste">{{ formatWeekday(godi.date) }}</th>
|
<th v-for="godi in props.gottesdienste">{{ formatWeekday(godi.date) }}</th>
|
||||||
|
<th class="edit" v-if="props.edit"></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</thead>
|
</thead>
|
||||||
@ -134,6 +167,7 @@ function getMinistrantClasses(mini: SimplifiedMinistrant) {
|
|||||||
<i class="icon"> {{ getIconForMark(godi.id, mini.id) }} </i><br>
|
<i class="icon"> {{ getIconForMark(godi.id, mini.id) }} </i><br>
|
||||||
<span class="hint">{{ getHintForMark(godi.id, mini.id) }}</span>
|
<span class="hint">{{ getHintForMark(godi.id, mini.id) }}</span>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="edit" v-if="props.edit"></td>
|
||||||
|
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@ -151,6 +185,9 @@ table {
|
|||||||
tr{
|
tr{
|
||||||
th{
|
th{
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
&.edit{
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&.bold th{
|
&.bold th{
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
|||||||
@ -1,24 +1,26 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
import {onMounted, reactive, ref, toRaw} from "vue";
|
import {onMounted, reactive, ref, toRaw, computed} from "vue";
|
||||||
import TablePlan from "@/components/TablePlan.vue";
|
import TablePlan from "@/components/TablePlan.vue";
|
||||||
import {API} from "@/views/api";
|
import {API} from "@/views/api";
|
||||||
import type {Mark, PlanModel} from "@/models/models";
|
import type {Gottesdienst, Mark, PlanModel, SimplifiedMinistrant} from "@/models/models";
|
||||||
import MobilePlan from "@/components/MobilePlan.vue";
|
import MobilePlan from "@/components/MobilePlan.vue";
|
||||||
import PlanActionBar from "@/components/PlanActionBar.vue";
|
import PlanActionBar from "@/components/PlanActionBar.vue";
|
||||||
|
|
||||||
import {computed, onMounted, reactive, ref} from "vue";
|
const plan = reactive<{
|
||||||
import Plan from "@/components/Plan.vue";
|
gottesdienste: Gottesdienst[],
|
||||||
import {API} from "@/views/api";
|
ministranten: SimplifiedMinistrant[],
|
||||||
import type {PlanModel} from "@/models/models";
|
marks: Mark[],
|
||||||
|
editable: number[]
|
||||||
const plan = reactive<PlanModel>({
|
}>({
|
||||||
gottesdienste: [],
|
gottesdienste: [],
|
||||||
ministranten: [],
|
ministranten: [],
|
||||||
marks: []
|
marks: [],
|
||||||
|
editable: []
|
||||||
})
|
})
|
||||||
const mobile = ref(false)
|
const mobile = ref(false)
|
||||||
const editedMarks = reactive<Mark[]>([]);
|
const editedMarks = reactive<Mark[]>([]);
|
||||||
|
const editPlanAdmin = ref(false)
|
||||||
|
|
||||||
const sortedGottesdienste = computed(() => {
|
const sortedGottesdienste = computed(() => {
|
||||||
return plan.gottesdienste.sort((a, b) => {
|
return plan.gottesdienste.sort((a, b) => {
|
||||||
@ -27,7 +29,8 @@ const sortedGottesdienste = computed(() => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
async function addGodi(data) {
|
async function addGodi(data, validate) {
|
||||||
|
console.log("Test")
|
||||||
console.log(data)
|
console.log(data)
|
||||||
let date = Date.parse(data.date + "T" + data.time);
|
let date = Date.parse(data.date + "T" + data.time);
|
||||||
let attendance = data.attendance && data.attendance != ""
|
let attendance = data.attendance && data.attendance != ""
|
||||||
@ -41,7 +44,8 @@ async function addGodi(data) {
|
|||||||
0
|
0
|
||||||
)
|
)
|
||||||
console.log(newGodi)
|
console.log(newGodi)
|
||||||
plan.gottesdienste.push(newGodi)
|
plan.gottesdienste.push(newGodi);
|
||||||
|
validate()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteGottedienst(id) {
|
async function deleteGottedienst(id) {
|
||||||
@ -53,13 +57,6 @@ async function deleteGottedienst(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function addGodi() {
|
|
||||||
let time = 1692104646066 + ((1000 * 60 * 60 * 24) * Math.random() * 6)
|
|
||||||
let newGodi = await API.addGottesdienst("Godi", new Date(time), new Date(time - 1000 * 60 * 30), 0)
|
|
||||||
plan.gottesdienste.push(newGodi)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
let fetchedPlan = await API.getPlan(0)
|
let fetchedPlan = await API.getPlan(0)
|
||||||
plan.gottesdienste = fetchedPlan.gottesdienste
|
plan.gottesdienste = fetchedPlan.gottesdienste
|
||||||
@ -111,9 +108,11 @@ function toggleMark(gid, mid) {
|
|||||||
:ministranten="plan.ministranten"
|
:ministranten="plan.ministranten"
|
||||||
:marks="getMarks()"
|
:marks="getMarks()"
|
||||||
:editable="plan.editable"
|
:editable="plan.editable"
|
||||||
|
:edit="editPlanAdmin"
|
||||||
@added="addGodi"
|
@added="addGodi"
|
||||||
@delete="deleteGottesdienst"
|
@delete="deleteGottedienst"
|
||||||
@toggle-mark="toggleMark"
|
@toggle-mark="toggleMark"
|
||||||
|
@end-edit="editPlanAdmin = false"
|
||||||
class="plan table"
|
class="plan table"
|
||||||
v-if="!mobile">
|
v-if="!mobile">
|
||||||
|
|
||||||
@ -134,7 +133,7 @@ function toggleMark(gid, mid) {
|
|||||||
class="action-bar"
|
class="action-bar"
|
||||||
:save="getDif().length > 0"
|
:save="getDif().length > 0"
|
||||||
:plan="false"
|
:plan="false"
|
||||||
:godi="false"
|
:godi="true"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,14 @@ async function api(endpoint: string, method: string = "GET", body?: any ) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setToken(token: string) {
|
||||||
|
let expires = new Date((new Date()).getTime() + (1000*60*60*24*5)).toUTCString()
|
||||||
|
document.cookie = `token=${token};expires=${expires};HTTPOnly`
|
||||||
|
}
|
||||||
|
|
||||||
|
function getToken(): string | null {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
export namespace API {
|
export namespace API {
|
||||||
|
|
||||||
@ -59,6 +67,23 @@ export namespace API {
|
|||||||
.then(data => data.status == 200)
|
.then(data => data.status == 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function login(username: string, password: string): Promise<{
|
||||||
|
success: boolean,
|
||||||
|
token?: string
|
||||||
|
}> {
|
||||||
|
return api("/auth", "POST", {
|
||||||
|
username, password
|
||||||
|
}).then(res => res.json() as Promise<{
|
||||||
|
success: boolean,
|
||||||
|
token?: string
|
||||||
|
}>)
|
||||||
|
.then(res => {
|
||||||
|
if(res.success) {
|
||||||
|
console.log("test")
|
||||||
|
}
|
||||||
|
return Promise.resolve(res)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user