165 lines
5.4 KiB
Python
Executable File
165 lines
5.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
from getpass import getpass
|
|
from os.path import dirname, expanduser
|
|
from requests.auth import AuthBase
|
|
from requests.exceptions import RequestException
|
|
from sys import exit, stderr
|
|
import gi
|
|
import json
|
|
import os
|
|
import platform
|
|
import requests
|
|
|
|
gi.require_version('Gtk', '3.0')
|
|
from gi.repository import Gtk
|
|
|
|
class Api:
|
|
class DeviceAuth(AuthBase):
|
|
def __init__(self, token):
|
|
self.token = token
|
|
|
|
def __call__(self, r):
|
|
r.headers['Authorization'] = f'Device {self.token}'
|
|
return r
|
|
|
|
def __init__(self, config):
|
|
self.config = config
|
|
|
|
def __call__(self, method, endpoint, **kwargs):
|
|
data = {'params' if method == 'GET' else 'json': kwargs}
|
|
r = requests.request(method, self.config['url'] + endpoint % self.config, auth=Api.DeviceAuth(self.config['api_token']), **data)
|
|
try:
|
|
r.raise_for_status()
|
|
except RequestException as e:
|
|
print(e, file=stderr)
|
|
print(r.text, file=stderr)
|
|
raise e
|
|
|
|
if r.headers['content-type'] == 'application/json':
|
|
return r.json()
|
|
|
|
return r.text
|
|
|
|
class Window(Gtk.Window):
|
|
def __init__(self, config):
|
|
super().__init__(title='Mark as paid')
|
|
|
|
self.config = config
|
|
self.api = Api(config)
|
|
|
|
self.entry = Gtk.Entry()
|
|
self.entry.set_width_chars(32)
|
|
self.entry.connect('activate', self.on_entry_activate)
|
|
self.add(self.entry)
|
|
|
|
def info(self, primary_text, secondary_text):
|
|
dialog = Gtk.MessageDialog(
|
|
transient_for=self,
|
|
flags=0,
|
|
message_type=Gtk.MessageType.INFO,
|
|
buttons=Gtk.ButtonsType.OK,
|
|
text=primary_text,
|
|
)
|
|
dialog.format_secondary_text(secondary_text)
|
|
dialog.run()
|
|
dialog.destroy()
|
|
|
|
def on_entry_activate(self, widget):
|
|
results = self.api('GET', '/api/v1/organizers/%(organizer)s/checkinrpc/search/', ignore_status='true', list=self.config['list'], search=widget.get_text())
|
|
widget.set_text('')
|
|
|
|
if results['count'] == 0:
|
|
self.info('Keine Ergebnisse', 'Bitte präzisiere deine Eingabe.')
|
|
return
|
|
if results['count'] > 1:
|
|
self.info('Mehrere Ergebnisse', 'Bitte präzisiere deine Eingabe.')
|
|
return
|
|
|
|
order = self.api('GET', f"/api/v1/organizers/%(organizer)s/events/%(event)s/orders/{results['results'][0]['order']}/")
|
|
if order['status'] == 'p':
|
|
self.info('Bereits bezahlt', 'Die Bestellung ist bereits bezahlt.')
|
|
return
|
|
if order['status'] == 'e':
|
|
self.info('Abgelaufen', 'Die Bestellung ist abgelaufen.')
|
|
return
|
|
if order['status'] == 'c':
|
|
self.info('Storniert', 'Die Bestellung wurde storniert.')
|
|
return
|
|
|
|
dialog = Gtk.MessageDialog(
|
|
transient_for=self,
|
|
flags=0,
|
|
message_type=Gtk.MessageType.QUESTION,
|
|
buttons=Gtk.ButtonsType.YES_NO,
|
|
text=f"Gesamtbetrag: {order['total']}",
|
|
)
|
|
dialog.format_secondary_text('Wurde der gesamte Betrag in bar entgegengenommen?')
|
|
|
|
response = dialog.run()
|
|
dialog.destroy()
|
|
|
|
if response == Gtk.ResponseType.YES:
|
|
try:
|
|
self.api('POST', f"/api/v1/organizers/%(organizer)s/events/%(event)s/orders/{results['results'][0]['order']}/mark_paid/")
|
|
self.info('Zahlung bestätigt', 'Die Zahlung wurde bestätigt, die Tickets sind nun gültig.')
|
|
except RequestException:
|
|
dialog = Gtk.MessageDialog(
|
|
transient_for=self,
|
|
flags=0,
|
|
message_type=Gtk.MessageType.ERROR,
|
|
buttons=Gtk.ButtonsType.OK,
|
|
text='Fehler',
|
|
)
|
|
dialog.format_secondary_text('Ein Fehler ist aufgetreten.')
|
|
dialog.run()
|
|
dialog.destroy()
|
|
|
|
if __name__ == '__main__':
|
|
config_path = expanduser('~/.config/pretix-markaspaid/config.json')
|
|
|
|
try:
|
|
with open(config_path) as f:
|
|
config = json.loads(f.read())
|
|
except FileNotFoundError:
|
|
handshake = json.loads(getpass('Please scan initialization qr code... '))
|
|
if handshake['handshake_version'] != 1:
|
|
print(f"Unknown handshake version {handshake['handshake_version']}", file=stderr)
|
|
exit(1)
|
|
|
|
r = requests.post(f"{handshake['url']}/api/v1/device/initialize", json={
|
|
'hardware_brand': platform.system(),
|
|
'hardware_model': platform.release(),
|
|
'software_brand': 'mark-as-paid',
|
|
'software_version': '0.1.0',
|
|
'token': handshake['token'],
|
|
})
|
|
try:
|
|
r.raise_for_status()
|
|
except RequestException as e:
|
|
print(e, file=stderr)
|
|
print(r.text, file=stderr)
|
|
exit(1)
|
|
|
|
r = r.json()
|
|
|
|
config = {
|
|
'api_token': r['api_token'],
|
|
'device_id': r['device_id'],
|
|
'event': input('Event: '),
|
|
'list': int(input('Check-in list: ')),
|
|
'organizer': r['organizer'],
|
|
'unique_serial': r['unique_serial'],
|
|
'url': handshake['url'],
|
|
}
|
|
|
|
os.makedirs(dirname(config_path))
|
|
with open(config_path, 'w') as f:
|
|
f.write(json.dumps(config))
|
|
|
|
window = Window(config)
|
|
window.connect('destroy', Gtk.main_quit)
|
|
window.show_all()
|
|
|
|
Gtk.main()
|