mirror of
https://codeberg.org/timelimit/timelimit-server-ui.git
synced 2025-10-02 17:09:14 +02:00
Add support for the new premium unlock API
This commit is contained in:
parent
c70c0d131a
commit
5d310c21d8
7 changed files with 180 additions and 5 deletions
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* TimeLimit Server Admin UI
|
||||
* Copyright (C) 2020 Jonas Lochmann
|
||||
* Copyright (C) 2020 - 2022 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as
|
||||
|
@ -22,6 +22,10 @@ export interface Api {
|
|||
mail: string
|
||||
duration: 'month' | 'year'
|
||||
}): Promise<void>
|
||||
unlockPremium2 (params: {
|
||||
purchaseId: string
|
||||
purchaseToken: string
|
||||
}): Promise<object>
|
||||
getStatusMessage (): Promise<string>
|
||||
setStatusMessage (newMessage: string): Promise<void>
|
||||
}
|
||||
|
|
|
@ -55,6 +55,16 @@ class DummyApiImpl implements Api {
|
|||
await delay(100 + Math.random() * 400)
|
||||
}
|
||||
|
||||
async unlockPremium2 () {
|
||||
await this.checkAuth()
|
||||
await delay(100 + Math.random() * 400)
|
||||
|
||||
return {
|
||||
ok: false,
|
||||
detail: 'dummy'
|
||||
}
|
||||
}
|
||||
|
||||
async getStatusMessage () {
|
||||
await this.checkAuth()
|
||||
await delay(100 + Math.random() * 400)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* TimeLimit Server Admin UI
|
||||
* Copyright (C) 2020 Jonas Lochmann
|
||||
* Copyright (C) 2020 - 2022 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as
|
||||
|
@ -110,6 +110,33 @@ class HttpApiImpl implements Api {
|
|||
await response.json()
|
||||
}
|
||||
|
||||
async unlockPremium2 ({ purchaseId, purchaseToken }: {
|
||||
purchaseId: string
|
||||
purchaseToken: string
|
||||
}): Promise<object> {
|
||||
const response = await fetch(this.serverUrl + '/unlock-premium-v2', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ purchaseId, purchaseToken }),
|
||||
mode: 'cors',
|
||||
cache: 'no-cache',
|
||||
referrerPolicy: 'no-referrer',
|
||||
headers: {
|
||||
Authorization: 'Basic ' + btoa(':' + this.token),
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
if (response.status === 401) {
|
||||
throw new IllegalAccessDataError()
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('unexpected response - ' + response.status)
|
||||
}
|
||||
|
||||
return await response.json()
|
||||
}
|
||||
|
||||
async getStatusMessage (): Promise<string> {
|
||||
const response = await fetch(this.serverUrl + '/status-message', {
|
||||
mode: 'cors',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* TimeLimit Server Admin UI
|
||||
* Copyright (C) 2020 Jonas Lochmann
|
||||
* Copyright (C) 2020 - 2022 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as
|
||||
|
@ -124,6 +124,32 @@ export const initAppController = ({ target, apiCreator }: {
|
|||
}
|
||||
}
|
||||
|
||||
view.unlockPremium2.listener = {
|
||||
onUnlockPremiumRequested: async ({ token, id }) => {
|
||||
view.unlockPremium2.isEnabled = false
|
||||
|
||||
try {
|
||||
const response = await api.unlockPremium2({
|
||||
purchaseId: id,
|
||||
purchaseToken: token
|
||||
})
|
||||
|
||||
view.unlockPremiumLog2.addMessage(
|
||||
id + ': ' + JSON.stringify(response, null, 2),
|
||||
1000 * 60 * 5
|
||||
)
|
||||
} catch (ex) {
|
||||
if (ex instanceof IllegalAccessDataError) {
|
||||
showAccessDataWrong()
|
||||
} else {
|
||||
view.unlockPremiumLog2.addMessage('could not unlock', view.unlockPremiumLog.short)
|
||||
}
|
||||
} finally {
|
||||
view.unlockPremium2.isEnabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this catches exceptions by itself
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
;(async () => {
|
||||
|
|
|
@ -20,11 +20,14 @@ import { LogView } from './logview'
|
|||
import { StatusView } from './status'
|
||||
import { StatusMessageForm } from './statusmessage'
|
||||
import { UnlockPremiumForm } from './unlockpremiumform'
|
||||
import { UnlockPremiumForm2 } from './unlockpremiumform2'
|
||||
|
||||
export class DetailScreen {
|
||||
status = new StatusView()
|
||||
unlockPremium = new UnlockPremiumForm()
|
||||
unlockPremiumLog = new LogView()
|
||||
unlockPremium2 = new UnlockPremiumForm2()
|
||||
unlockPremiumLog2 = new LogView()
|
||||
statusMessage = new StatusMessageForm()
|
||||
statusMessageLog = new LogView()
|
||||
root = document.createElement('div')
|
||||
|
@ -36,6 +39,10 @@ export class DetailScreen {
|
|||
this.unlockPremium.root,
|
||||
this.unlockPremiumLog.root
|
||||
),
|
||||
wrapInBorder(
|
||||
this.unlockPremium2.root,
|
||||
this.unlockPremiumLog2.root
|
||||
),
|
||||
wrapInBorder(
|
||||
this.statusMessage.root,
|
||||
this.statusMessageLog.root
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* TimeLimit Server Admin UI
|
||||
* Copyright (C) 2020 Jonas Lochmann
|
||||
* Copyright (C) 2020 - 2022 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as
|
||||
|
@ -33,7 +33,7 @@ export class LogView {
|
|||
|
||||
view.innerText = message
|
||||
|
||||
this.root.appendChild(view)
|
||||
this.root.prepend(view)
|
||||
|
||||
if (duration) {
|
||||
setTimeout(() => {
|
||||
|
|
101
src/view/unlockpremiumform2.ts
Normal file
101
src/view/unlockpremiumform2.ts
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* TimeLimit Server Admin UI
|
||||
* Copyright (C) 2020 - 2022 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { createHeader } from './header'
|
||||
import { RadioButton } from './radio'
|
||||
|
||||
function getPurchaseIdPlaceholder(): string {
|
||||
const now = new Date()
|
||||
|
||||
const day = now.getDate().toString().padStart(2, '0')
|
||||
const month = (now.getMonth() + 1).toString().padStart(2, '0')
|
||||
const year = now.getFullYear().toString()
|
||||
|
||||
return [year, month, day, 'XYZ'].join('-')
|
||||
}
|
||||
|
||||
export class UnlockPremiumForm2 {
|
||||
listener?: UnlockPremiumFormListener = undefined
|
||||
readonly root: HTMLElement
|
||||
private readonly form: HTMLFormElement
|
||||
private readonly purchaseIdField: HTMLInputElement
|
||||
private readonly purchaseTokenField: HTMLTextAreaElement
|
||||
private readonly submitButton: HTMLInputElement
|
||||
private enabled: boolean = true
|
||||
|
||||
constructor () {
|
||||
this.form = document.createElement('form')
|
||||
this.purchaseIdField = document.createElement('input')
|
||||
this.purchaseTokenField = document.createElement('textarea')
|
||||
this.submitButton = document.createElement('input')
|
||||
|
||||
this.purchaseIdField.placeholder = getPurchaseIdPlaceholder()
|
||||
this.purchaseIdField.value = getPurchaseIdPlaceholder()
|
||||
|
||||
this.purchaseTokenField.rows = 10
|
||||
|
||||
this.submitButton.type = 'submit'
|
||||
this.submitButton.value = 'Unlock'
|
||||
|
||||
this.reset()
|
||||
|
||||
this.form.addEventListener('submit', (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
const id = this.purchaseIdField.value
|
||||
const token = this.purchaseTokenField.value
|
||||
|
||||
if (id.endsWith('XYZ')) return alert('placeholder token used')
|
||||
|
||||
this.listener?.onUnlockPremiumRequested({ token, id })
|
||||
})
|
||||
|
||||
this.form.append(
|
||||
createHeader('Unlock premium version (new)'),
|
||||
this.purchaseIdField,
|
||||
this.purchaseTokenField,
|
||||
this.submitButton
|
||||
)
|
||||
|
||||
this.root = this.form
|
||||
}
|
||||
|
||||
reset () {
|
||||
this.purchaseIdField.value = getPurchaseIdPlaceholder()
|
||||
this.purchaseTokenField.value = ''
|
||||
this.isEnabled = true
|
||||
}
|
||||
|
||||
set isEnabled (value: boolean) {
|
||||
if (value === this.enabled) {
|
||||
return
|
||||
}
|
||||
|
||||
this.enabled = value
|
||||
|
||||
this.purchaseIdField.disabled = !value
|
||||
this.purchaseTokenField.isEnabled = value
|
||||
this.submitButton.disabled = !value
|
||||
}
|
||||
}
|
||||
|
||||
interface UnlockPremiumFormListener {
|
||||
onUnlockPremiumRequested (params: {
|
||||
token: string
|
||||
id: string
|
||||
}): void
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue