diff --git a/data/device_database.go b/data/device_database.go
index 3c802a7..48d1068 100644
--- a/data/device_database.go
+++ b/data/device_database.go
@@ -4,7 +4,6 @@ import (
"database/sql"
"fmt"
"path/filepath"
- "time"
gonanoid "github.com/matoous/go-nanoid"
_ "github.com/mattn/go-sqlite3"
@@ -31,11 +30,10 @@ func (db *DeviceDatabase) Initialize() error {
return fmt.Errorf("error creating devices table: %s", error)
}
- _, error = db.Connection.Exec(`CREATE TABLE IF NOT EXISTS sessions (
- token TEXT PRIMARY KEY,
- device_id INTEGER,
- expiry_date TIMESTAMP,
- FOREIGN KEY (device_id) REFERENCES devices(id)
+ _, error = db.Connection.Exec(`CREATE TABLE IF NOT EXISTS integrations (
+ id TEXT PRIMARY KEY,
+ name TEXT UNIQUE,
+ token TEXT
)`)
if error != nil {
return fmt.Errorf("error creating device sessions table: %s", error)
@@ -55,18 +53,6 @@ func (db *DeviceDatabase) CreateDevice(device_name string, description string) (
return deviceID, err
}
-func (db *DeviceDatabase) CreateSession(deviceID string, expiryDate time.Time) (string, error) {
- sessionToken, err := gonanoid.Nanoid(16)
- if err != nil {
- return "", err
- }
- _, err = db.Connection.Exec("INSERT INTO sessions (device_id, token, expiry_date) VALUES (?, ?, ?)", deviceID, sessionToken, expiryDate)
- if err != nil {
- return "", err
- }
- return sessionToken, nil
-}
-
func (db *DeviceDatabase) GetDeviceById(id string) (*PlaybackDevice, error) {
var device PlaybackDevice
err := db.Connection.QueryRow("SELECT id, device_name, description FROM devices WHERE id = ?", id).Scan(&device.ID, &device.Name, &device.Description)
@@ -90,24 +76,6 @@ func (db *DeviceDatabase) UpdateDevice(device *PlaybackDevice) error {
return err
}
-func (db *DeviceDatabase) GetSession(sessionToken string) (*DeviceSession, error) {
- var session DeviceSession
- row := db.Connection.QueryRow("SELECT token, device_id, expiry_date FROM sessions WHERE token = ?", sessionToken)
- err := row.Scan(&session.Token, &session.DeviceID, &session.ExpiryDate)
- if err != nil {
- if err == sql.ErrNoRows {
- return nil, nil
- }
- return nil, err
- }
- return &session, nil
-}
-
-func (db *DeviceDatabase) DeleteSessionByToken(token string) error {
- _, err := db.Connection.Exec("DELETE FROM sessions WHERE token = ?", token)
- return err
-}
-
func (db *DeviceDatabase) GetDevices() (*[]PlaybackDevice, error) {
var devices []PlaybackDevice
@@ -136,6 +104,47 @@ func (db *DeviceDatabase) DeleteDevice(ID string) error {
return err
}
+func (db *DeviceDatabase) CreateIntegration(name string) (string, string, error) {
+ id, err := gonanoid.Nanoid(10)
+ if err != nil {
+ return "", "", err
+ }
+
+ token, err := gonanoid.Nanoid(16)
+ if err != nil {
+ return "", "", err
+ }
+
+ hashed_token, err := hashPassword(token)
+ if err != nil {
+ return "", "", err
+ }
+
+ _, err = db.Connection.Exec("INSERT INTO integrations (id, name, token) VALUES (?, ?, ?)", id, name, hashed_token)
+ if err != nil {
+ return "", "", err
+ }
+ return id, token, nil
+}
+
+func (db *DeviceDatabase) GetSession(sessionToken string) (*DeviceSession, error) {
+ var session DeviceSession
+ row := db.Connection.QueryRow("SELECT token, device_id, expiry_date FROM sessions WHERE token = ?", sessionToken)
+ err := row.Scan(&session.Token, &session.DeviceID, &session.ExpiryDate)
+ if err != nil {
+ if err == sql.ErrNoRows {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &session, nil
+}
+
+func (db *DeviceDatabase) DeleteSessionByToken(token string) error {
+ _, err := db.Connection.Exec("DELETE FROM sessions WHERE token = ?", token)
+ return err
+}
+
func (db *DeviceDatabase) SetDirectory(directory string) {
db.databaseDirectory = directory
}
diff --git a/management/device_manager.go b/management/device_manager.go
index 98f6b23..a3c9132 100644
--- a/management/device_manager.go
+++ b/management/device_manager.go
@@ -2,10 +2,13 @@ package management
import (
d "playback-device-server/data"
+
+ gonanoid "github.com/matoous/go-nanoid"
)
type DeviceManager struct {
- deviceDatabase *d.DeviceDatabase
+ deviceDatabase *d.DeviceDatabase
+ registrationCodes []string
}
func (um *DeviceManager) Initialize(deviceDatabase *d.DeviceDatabase) error {
@@ -82,3 +85,9 @@ func (um *DeviceManager) DeleteDevice(ID string) error {
error := um.deviceDatabase.DeleteDevice(ID)
return error
}
+
+func (um *DeviceManager) GetRegistrationCode() (string, error) {
+ code := gonanoid.MustGenerate("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 6)
+ um.registrationCodes = append(um.registrationCodes, code)
+ return code, nil
+}
diff --git a/server/device_api_handler.go b/server/device_api_handler.go
index 878d835..65a0440 100644
--- a/server/device_api_handler.go
+++ b/server/device_api_handler.go
@@ -15,14 +15,33 @@ type DeviceApiHandler struct {
func (r *DeviceApiHandler) Initialize(authenticator *Authenticator) {
r.router.Use(authenticator.Authenticate("/api/devices", []string{}))
- usersApi := r.router.Group("/api/devices")
+ devicesApi := r.router.Group("/api/devices")
//usersApi.POST("/register", r.handleRegister)
//usersApi.POST("/deregister", r.handleDeregister)
- usersApi.GET("/session/info", r.handleGetSessionInfo)
- usersApi.PUT("/:id", r.handleUpdateConfig)
- usersApi.GET("", r.handleGetDevices)
- usersApi.POST("", r.handleCreateDevice)
- usersApi.DELETE("/:id", r.handleDeleteDevice)
+ devicesApi.GET("/session/info", r.handleGetSessionInfo)
+ devicesApi.PUT("/:id", r.handleUpdateConfig)
+ devicesApi.GET("", r.handleGetDevices)
+ devicesApi.POST("", r.handleCreateDevice)
+ devicesApi.DELETE("/:id", r.handleDeleteDevice)
+ integrationsApi := r.router.Group("/api/integrations")
+ integrationsApi.GET("/register", r.handleIntegrationRegistration)
+}
+
+func (r *DeviceApiHandler) handleIntegrationRegistration(context echo.Context) error {
+ code, error := r.deviceManager.GetRegistrationCode()
+
+ if error != nil {
+ SendError(500, context, fmt.Sprintf("failed to get registration code: %s", error))
+ return error
+ }
+
+ response := struct {
+ Code string `json:"code"`
+ }{
+ Code: code,
+ }
+
+ return context.JSON(200, response)
}
//func (r DeviceApiHandler) handleRegister(context echo.Context) error {
diff --git a/www/src/modals/modal-handler.js b/www/src/modals/modal-handler.js
index 0ccd7db..2f7f35a 100644
--- a/www/src/modals/modal-handler.js
+++ b/www/src/modals/modal-handler.js
@@ -19,12 +19,26 @@ function ModalHandler() {
function setModalId(modalId) {
_modalId = modalId;
}
+
+ function onHidden(callback) {
+ _ref.addEventListener('hidden.bs.modal', () => {
+ callback();
+ });
+ }
+
+ function onShow(callback) {
+ _ref.addEventListener('show.bs.modal', () => {
+ callback();
+ });
+ }
return {
setRef,
show,
hide,
setModalId,
+ onHidden,
+ onShow,
};
}
diff --git a/www/src/modals/modal-registry.jsx b/www/src/modals/modal-registry.jsx
index eb531c1..84f9829 100644
--- a/www/src/modals/modal-registry.jsx
+++ b/www/src/modals/modal-registry.jsx
@@ -4,6 +4,7 @@ import CreateUserModal from "./create-user-modal.jsx";
import DeleteUserModal from "./delete-user-modal.jsx";
import UserSettingsModal from "./user-settings-modal.jsx";
import CreateDeviceModal from "./create-device-modal.jsx";
+import ShowRegistrationCodeModal from "./show-registration-code-modal.jsx";
const ModalRegistry = (function () {
const modals = [
@@ -27,6 +28,11 @@ const ModalRegistry = (function () {
component: CreateDeviceModal,
ref: null,
},
+ {
+ id: "showRegistrationCodeModal",
+ component: ShowRegistrationCodeModal,
+ ref: null,
+ },
];
function getModals(props) {
diff --git a/www/src/modals/show-registration-code-modal.jsx b/www/src/modals/show-registration-code-modal.jsx
new file mode 100644
index 0000000..c983fae
--- /dev/null
+++ b/www/src/modals/show-registration-code-modal.jsx
@@ -0,0 +1,66 @@
+import {
+ createEffect,
+ createSignal,
+ Show,
+ createResource,
+ onMount,
+} from "solid-js";
+import Modal from "./modal.jsx";
+import ModalHandler from "./modal-handler.js";
+import DeviceService from "../services/device-service.js";
+
+function ShowRegistrationCodeModal(props) {
+ const [error, setError] = createSignal("");
+ const [code, { mutate, refetch }] = createResource(async () =>
+ DeviceService.getRegistrationCode()
+ );
+
+ onMount(() => {
+ ShowRegistrationCodeModal.Handler.onHidden(() => mutate(null));
+ ShowRegistrationCodeModal.Handler.onShow(() => refetch());
+ });
+
+ function handleClose() {
+ ShowRegistrationCodeModal.Handler.hide();
+ }
+
+ return (
+