Add support for the new premium unlock API

This commit is contained in:
Jonas Lochmann 2022-09-26 02:00:00 +02:00
parent c70c0d131a
commit 5d310c21d8
No known key found for this signature in database
GPG key ID: 8B8C9AEE10FA5B36
7 changed files with 180 additions and 5 deletions

View file

@ -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>
}

View file

@ -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)

View file

@ -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',

View file

@ -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 () => {

View file

@ -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

View file

@ -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(() => {

View 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
}