feat: add create integration with code
This commit is contained in:
parent
d869e8d119
commit
54a2b7418a
@ -104,27 +104,31 @@ func (db *DeviceDatabase) DeleteDevice(ID string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DeviceDatabase) CreateIntegration(name string) (string, string, error) {
|
||||
func (db *DeviceDatabase) CreateIntegration(name, token string) (string, error) {
|
||||
id, err := gonanoid.Nanoid(10)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
token, err := gonanoid.Nanoid(16)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
return "", err
|
||||
}
|
||||
|
||||
hashed_token, err := hashPassword(token)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
return "", err
|
||||
}
|
||||
|
||||
_, err = db.Connection.Exec("INSERT INTO integrations (id, name, token) VALUES (?, ?, ?)", id, name, hashed_token)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
return "", err
|
||||
}
|
||||
return id, token, nil
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (db *DeviceDatabase) IntegrationNameExists(name string) (bool, error) {
|
||||
var exists bool
|
||||
err := db.Connection.QueryRow("SELECT EXISTS(SELECT 1 FROM integrations WHERE name = ?)", name).Scan(&exists)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
func (db *DeviceDatabase) GetSession(sessionToken string) (*DeviceSession, error) {
|
||||
|
||||
7
data/integration.go
Normal file
7
data/integration.go
Normal file
@ -0,0 +1,7 @@
|
||||
package data
|
||||
|
||||
type Integration struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
@ -1,7 +1,9 @@
|
||||
package management
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
d "playback-device-server/data"
|
||||
"slices"
|
||||
|
||||
gonanoid "github.com/matoous/go-nanoid"
|
||||
)
|
||||
@ -87,7 +89,68 @@ func (um *DeviceManager) DeleteDevice(ID string) error {
|
||||
}
|
||||
|
||||
func (um *DeviceManager) GetRegistrationCode() (string, error) {
|
||||
code := gonanoid.MustGenerate("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 6)
|
||||
um.registrationCodes = append(um.registrationCodes, code)
|
||||
code := um.createCode()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (um *DeviceManager) CreateIntegration(name, code string) (d.Integration, error) {
|
||||
exists, err := um.deviceDatabase.IntegrationNameExists(name)
|
||||
if err != nil {
|
||||
return d.Integration{}, err
|
||||
}
|
||||
if exists {
|
||||
return d.Integration{}, fmt.Errorf("Integration name already exists")
|
||||
}
|
||||
|
||||
if err := um.redeemCode(code); err != nil {
|
||||
return d.Integration{}, err
|
||||
}
|
||||
|
||||
token, err := gonanoid.Nanoid(16)
|
||||
if err != nil {
|
||||
return d.Integration{}, err
|
||||
}
|
||||
|
||||
id, err := um.deviceDatabase.CreateIntegration(name, token)
|
||||
if err != nil {
|
||||
return d.Integration{}, err
|
||||
}
|
||||
|
||||
integration := d.Integration{
|
||||
ID: id,
|
||||
Name: name,
|
||||
Token: token,
|
||||
}
|
||||
|
||||
return integration, nil
|
||||
}
|
||||
|
||||
func (um *DeviceManager) checkCode(code string) bool {
|
||||
for _, c := range um.registrationCodes {
|
||||
if c == code {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (um *DeviceManager) createCode() string {
|
||||
code := gonanoid.MustGenerate("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 6)
|
||||
um.registrationCodes = append(um.registrationCodes, code)
|
||||
return code
|
||||
}
|
||||
|
||||
func (um *DeviceManager) redeemCode(code string) error {
|
||||
if !um.checkCode(code) {
|
||||
return fmt.Errorf("Invalid registration code")
|
||||
}
|
||||
|
||||
for i, c := range um.registrationCodes {
|
||||
if c == code {
|
||||
um.registrationCodes = slices.Delete(um.registrationCodes, i, i+1)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ func (r *DeviceApiHandler) Initialize(authenticator *Authenticator) {
|
||||
devicesApi.DELETE("/:id", r.handleDeleteDevice)
|
||||
integrationsApi := r.router.Group("/api/integrations")
|
||||
integrationsApi.GET("/register", r.handleIntegrationRegistration)
|
||||
integrationsApi.POST("", r.handleCreateIntegration)
|
||||
}
|
||||
|
||||
func (r *DeviceApiHandler) handleIntegrationRegistration(context echo.Context) error {
|
||||
@ -44,6 +45,28 @@ func (r *DeviceApiHandler) handleIntegrationRegistration(context echo.Context) e
|
||||
return context.JSON(200, response)
|
||||
}
|
||||
|
||||
func (r *DeviceApiHandler) handleCreateIntegration(context echo.Context) error {
|
||||
var data struct {
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
}
|
||||
error := context.Bind(&data)
|
||||
|
||||
if error != nil {
|
||||
SendError(500, context, fmt.Sprintf("Failed to create integration: %s", error))
|
||||
return error
|
||||
}
|
||||
|
||||
integration, error := r.deviceManager.CreateIntegration(data.Name, data.Code)
|
||||
|
||||
if error != nil {
|
||||
SendError(400, context, fmt.Sprintf("Failed to create integration: %s", error))
|
||||
return error
|
||||
}
|
||||
|
||||
return context.JSON(200, integration)
|
||||
}
|
||||
|
||||
//func (r DeviceApiHandler) handleRegister(context echo.Context) error {
|
||||
// var registrationData struct {
|
||||
// Code string `json:"code"`
|
||||
|
||||
92
www/integration.html
Normal file
92
www/integration.html
Normal file
@ -0,0 +1,92 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de" data-bs-theme="dark">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<title>Integration</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<div style="padding: 1em; border: 1px solid #444">
|
||||
<p style="font-weight: bold">Register</p>
|
||||
<label for="register-name">Name:</label>
|
||||
<input type="text" id="register-name" name="register-name" required />
|
||||
<label for="register-code">Code:</label>
|
||||
<input type="text" id="register-code" name="register-code" required />
|
||||
<button id="register-button">Register</button>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module">
|
||||
let registerButton = document.getElementById("register-button");
|
||||
registerButton.addEventListener("click", register);
|
||||
async function register() {
|
||||
let name = document.getElementById("register-name").value;
|
||||
let code = document.getElementById("register-code").value;
|
||||
console.log("Registering with name:", name, "and code:", code);
|
||||
let response = await sendJsonRequest({
|
||||
method: "POST",
|
||||
url: "/api/integrations",
|
||||
data: { name, code },
|
||||
});
|
||||
|
||||
if (response.status === 200) {
|
||||
console.log("Registration successful");
|
||||
console.log(JSON.parse(response.data));
|
||||
} else {
|
||||
console.error("Registration failed with status code:", response.status);
|
||||
console.log(JSON.parse(response.data));
|
||||
}
|
||||
}
|
||||
|
||||
async function sendJsonRequest({ method, url, data, headers }) {
|
||||
if (typeof data !== "string") {
|
||||
data = JSON.stringify(data);
|
||||
}
|
||||
if (!headers) headers = {};
|
||||
headers["Content-Type"] = "application/json";
|
||||
return sendRequest({ method, url, data, headers });
|
||||
}
|
||||
|
||||
async function sendRequest({ method, url, data, headers, queryParams }) {
|
||||
if (queryParams) {
|
||||
let params = new URLSearchParams();
|
||||
for (var queryParam in queryParams) {
|
||||
params.append(queryParam, queryParams[queryParam]);
|
||||
}
|
||||
let queryString = params.toString();
|
||||
queryString = queryString ? "?" + queryString : "";
|
||||
url = url + queryString;
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
let xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.addEventListener("load", function () {
|
||||
resolve({ status: xhr.status, data: xhr.response });
|
||||
});
|
||||
|
||||
xhr.addEventListener("readystatechange", function () {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
resolve({ status: xhr.status, data: xhr.response });
|
||||
}
|
||||
});
|
||||
|
||||
xhr.addEventListener("error", function () {
|
||||
reject(xhr.response);
|
||||
});
|
||||
|
||||
xhr.open(method, url, true);
|
||||
for (var header in headers) {
|
||||
xhr.setRequestHeader(header, headers[header]);
|
||||
}
|
||||
|
||||
try {
|
||||
xhr.send(data);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -5,7 +5,7 @@
|
||||
"scripts": {
|
||||
"start": "vite",
|
||||
"dev": "vite",
|
||||
"build": "rm -rf dist; vite build && cp -r src/lib dist",
|
||||
"build": "rm -rf dist; vite build && cp -r src/lib dist; cp integration.html dist",
|
||||
"serve": "vite preview"
|
||||
},
|
||||
"license": "MIT",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user