Browse Source

feat: wpa3 개발

v2
최원형 1 month ago
parent
commit
55f70b8ea3
  1. 22
      src/main/java/org/mobidgim/mobidigimproject/MobidigimProjectApplication.java
  2. 24
      src/main/java/org/mobidgim/mobidigimproject/config/DatabaseInitializer.java
  3. 15
      src/main/java/org/mobidgim/mobidigimproject/model/device/enums/WiFiSecurity.java
  4. 4
      src/main/resources/static/css/style.css
  5. 7
      src/main/resources/static/index.html
  6. 7
      src/main/resources/static/js/device/deviceData.js
  7. 29
      src/main/resources/static/js/device/ssid.js
  8. 64
      src/main/resources/static/js/main.js

22
src/main/java/org/mobidgim/mobidigimproject/MobidigimProjectApplication.java

@ -2,13 +2,6 @@ package org.mobidgim.mobidigimproject;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@SpringBootApplication @SpringBootApplication
// (exclude = { // (exclude = {
// DataSourceAutoConfiguration.class, // DataSourceAutoConfiguration.class,
@ -18,21 +11,6 @@ import java.nio.file.Paths;
public class MobidigimProjectApplication { public class MobidigimProjectApplication {
public static void main(String[] args) { public static void main(String[] args) {
ensureDbDirectory();
SpringApplication.run(MobidigimProjectApplication.class, args); SpringApplication.run(MobidigimProjectApplication.class, args);
} }
private static void ensureDbDirectory() {
try {
Path dbDir = Paths.get(System.getProperty("user.home"), "db");
Files.createDirectories(dbDir);
Path dbFile = dbDir.resolve("dynamic_data.db");
if (Files.notExists(dbFile)) {
Files.createFile(dbFile);
}
} catch (Exception e) {
throw new IllegalStateException("Failed to prepare SQLite DB file", e);
}
}
} }

24
src/main/java/org/mobidgim/mobidigimproject/config/DatabaseInitializer.java

@ -1,24 +0,0 @@
package org.mobidgim.mobidigimproject.config;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class DatabaseInitializer implements ApplicationRunner {
private final JdbcTemplate jdbcTemplate;
@Override
public void run(ApplicationArguments args) {
jdbcTemplate.execute(
"CREATE TABLE IF NOT EXISTS board_config (" +
"\"key\" TEXT PRIMARY KEY, " +
"\"value\" TEXT NOT NULL" +
")"
);
}
}

15
src/main/java/org/mobidgim/mobidigimproject/model/device/enums/WiFiSecurity.java

@ -1,14 +1,27 @@
package org.mobidgim.mobidigimproject.model.device.enums; package org.mobidgim.mobidigimproject.model.device.enums;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@AllArgsConstructor @AllArgsConstructor
public enum WiFiSecurity { public enum WiFiSecurity {
NONE("none"), NONE("none"),
WPA_WPA2("wpa/wpa2"); WPA_WPA2("wpa/wpa2"),
WPA3("wpa3");
private final String value; private final String value;
@JsonCreator
public static WiFiSecurity fromValue(String value) {
for (WiFiSecurity security : values()) {
if (security.value.equalsIgnoreCase(String.valueOf(value).trim())) {
return security;
}
}
throw new IllegalArgumentException("Invalid wifiSecurity value: " + value);
}
@JsonValue @JsonValue
public String getValue() { public String getValue() {
return value; return value;

4
src/main/resources/static/css/style.css

@ -210,7 +210,9 @@ details.nav {
} }
.ssid-row select { .ssid-row select {
width: 100px; width: 140px;
min-width: 140px;
flex: 0 0 140px;
padding: 6px 8px; padding: 6px 8px;
font-size: 16px; font-size: 16px;
border: 1px solid #aaa; border: 1px solid #aaa;

7
src/main/resources/static/index.html

@ -75,6 +75,7 @@
<select> <select>
<option value="none">NONE</option> <option value="none">NONE</option>
<option value="wpa/wpa2">WPA/WPA2</option> <option value="wpa/wpa2">WPA/WPA2</option>
<option value="wpa3">WPA3</option>
</select> </select>
</div> </div>
</template> </template>
@ -170,7 +171,7 @@
<div class="io-fieldset"> <div class="io-fieldset">
<div class="io-row"><span class="label-inline">Mode</span><span class="colon">:</span> <div class="io-row"><span class="label-inline">Mode</span><span class="colon">:</span>
<select id="rs485_mode"> <select id="rs485_mode">
<option value="">NONE</option> <option value="" selected disabled hidden></option>
<option value="half">half</option> <option value="half">half</option>
<option value="full">full</option> <option value="full">full</option>
</select> </select>
@ -199,7 +200,7 @@
<div class="io-fieldset"> <div class="io-fieldset">
<div class="io-row"><span class="label-inline">Can Type</span><span class="colon">:</span> <div class="io-row"><span class="label-inline">Can Type</span><span class="colon">:</span>
<select id="can_bus_type"> <select id="can_bus_type">
<option value="">NONE</option> <option value="" selected disabled hidden></option>
<option value="extended">extended</option> <option value="extended">extended</option>
<option value="standard">standard</option> <option value="standard">standard</option>
</select> </select>
@ -207,7 +208,7 @@
<div class="io-row"><span class="label-inline">Can Speed</span><span class="colon">:</span> <div class="io-row"><span class="label-inline">Can Speed</span><span class="colon">:</span>
<select id="can_baudrate"> <select id="can_baudrate">
<option value="">NONE</option> <option value="">AUTO</option>
<option value="100">100kb/s</option> <option value="100">100kb/s</option>
<option value="250">250kb/s</option> <option value="250">250kb/s</option>
<option value="500">500kb/s</option> <option value="500">500kb/s</option>

7
src/main/resources/static/js/device/deviceData.js

@ -48,6 +48,10 @@ export function createDeviceDataController({ ssidController }) {
toggleNetInputs(); toggleNetInputs();
} }
function loadDefaults() {
loadFromData(cloneDeviceDefaults());
}
function collectDeviceData() { function collectDeviceData() {
const result = cloneDeviceDefaults(); const result = cloneDeviceDefaults();
@ -87,12 +91,13 @@ export function createDeviceDataController({ ssidController }) {
function initialize() { function initialize() {
bindEvents(); bindEvents();
loadFromData(); toggleNetInputs();
} }
return { return {
collectDeviceData, collectDeviceData,
initialize, initialize,
loadDefaults,
loadFromData, loadFromData,
toggleNetInputs, toggleNetInputs,
}; };

29
src/main/resources/static/js/device/ssid.js

@ -1,12 +1,32 @@
import { cloneTemplateRow } from '../utils/dom.js'; import { cloneTemplateRow } from '../utils/dom.js';
export function createSsidController({ listElement, templateElement, addButton, countryCodeInput }) { export function createSsidController({ listElement, templateElement, addButton, countryCodeInput }) {
function syncPasswordState(row) {
const passwordInput = row.querySelector('.ssid-pw');
const toggleButton = row.querySelector('.toggle-pw');
const securitySelect = row.querySelector('select');
const isNoneSecurity = (securitySelect?.value ?? 'none').toLowerCase() === 'none';
passwordInput.disabled = isNoneSecurity;
if (isNoneSecurity) {
passwordInput.value = '';
passwordInput.type = 'password';
}
if (toggleButton) {
toggleButton.disabled = isNoneSecurity;
toggleButton.textContent = 'show';
}
}
function createRow(values = { wifi_ssid: '', wifi_passwd: '', wifi_security: 'none' }) { function createRow(values = { wifi_ssid: '', wifi_passwd: '', wifi_security: 'none' }) {
const row = cloneTemplateRow(templateElement); const row = cloneTemplateRow(templateElement);
row.querySelector('.ssid-name').value = values.wifi_ssid ?? ''; row.querySelector('.ssid-name').value = values.wifi_ssid ?? '';
row.querySelector('.ssid-pw').value = values.wifi_passwd ?? ''; row.querySelector('.ssid-pw').value = values.wifi_passwd ?? '';
row.querySelector('select').value = (values.wifi_security ?? 'none').toLowerCase(); row.querySelector('select').value = (values.wifi_security ?? 'none').toLowerCase();
syncPasswordState(row);
const deleteButton = document.createElement('button'); const deleteButton = document.createElement('button');
deleteButton.type = 'button'; deleteButton.type = 'button';
@ -61,6 +81,9 @@ export function createSsidController({ listElement, templateElement, addButton,
listElement.addEventListener('click', (event) => { listElement.addEventListener('click', (event) => {
if (event.target.classList.contains('toggle-pw')) { if (event.target.classList.contains('toggle-pw')) {
const passwordInput = event.target.closest('.ssid-row').querySelector('.ssid-pw'); const passwordInput = event.target.closest('.ssid-row').querySelector('.ssid-pw');
if (passwordInput.disabled) {
return;
}
passwordInput.type = passwordInput.type === 'password' ? 'text' : 'password'; passwordInput.type = passwordInput.type === 'password' ? 'text' : 'password';
event.target.textContent = passwordInput.type === 'password' ? 'show' : 'hide'; event.target.textContent = passwordInput.type === 'password' ? 'show' : 'hide';
return; return;
@ -71,6 +94,12 @@ export function createSsidController({ listElement, templateElement, addButton,
} }
}); });
listElement.addEventListener('change', (event) => {
if (event.target.matches('.ssid-row select')) {
syncPasswordState(event.target.closest('.ssid-row'));
}
});
countryCodeInput?.addEventListener('input', () => { countryCodeInput?.addEventListener('input', () => {
countryCodeInput.value = countryCodeInput.value countryCodeInput.value = countryCodeInput.value
.replace(/[^a-zA-Z]/g, '') .replace(/[^a-zA-Z]/g, '')

64
src/main/resources/static/js/main.js

@ -11,6 +11,56 @@ import { createProtocolDataController } from './protocol/protocolData.js';
import { getRegisterConfigValidationError, isValidRegisterConfig } from './protocol/protocolValidation.js'; import { getRegisterConfigValidationError, isValidRegisterConfig } from './protocol/protocolValidation.js';
import { byId, queryAll } from './utils/dom.js'; import { byId, queryAll } from './utils/dom.js';
function notifyLoadFailure(target, error) {
const statusMatch = /Request failed: (\d+)/.exec(String(error?.message ?? ''));
const statusText = statusMatch ? ` (HTTP ${statusMatch[1]})` : '';
const message = `${target} settings could not be loaded${statusText}. Please check the saved data on the backend.`;
console.error(message, error);
alert(message);
}
function isLegacySuccessMessage(data) {
return String(data?.message ?? '').trim().toLowerCase() === 'success';
}
function isLegacyProtocolPayload(data) {
if (!data || typeof data !== 'object' || Array.isArray(data)) {
return false;
}
return [
'protocol',
'dev_type',
'can_input',
'dr_on',
'odo_on',
'MEID',
'MODBUS',
'OPC_UA',
'CAN',
].some((key) => Object.prototype.hasOwnProperty.call(data, key));
}
function isSaveSuccessful(type, response) {
if (!response.ok) {
return false;
}
if (response.data?.success === true) {
return true;
}
if (type === 'device' && isLegacySuccessMessage(response.data)) {
return true;
}
if (type === 'protocol' && isLegacyProtocolPayload(response.data)) {
return true;
}
return false;
}
async function initializeApp() { async function initializeApp() {
const navigation = createNavigation(); const navigation = createNavigation();
const ssidController = createSsidController({ const ssidController = createSsidController({
@ -49,7 +99,9 @@ async function initializeApp() {
protocolController.loadFromRegisterJson(data); protocolController.loadFromRegisterJson(data);
}, },
getDownloadData: () => protocolController.collectProtocolData(), getDownloadData: () => protocolController.normalizeRegisterForPost(
protocolController.collectProtocolData(),
),
}); });
queryAll('.save-file').forEach((button) => { queryAll('.save-file').forEach((button) => {
@ -71,8 +123,8 @@ async function initializeApp() {
saveProtocolConfig(protocolPayload), saveProtocolConfig(protocolPayload),
]); ]);
const isDeviceSaved = deviceResponse.ok && deviceResponse.data?.success === true; const isDeviceSaved = isSaveSuccessful('device', deviceResponse);
const isProtocolSaved = protocolResponse.ok && protocolResponse.data?.success === true; const isProtocolSaved = isSaveSuccessful('protocol', protocolResponse);
if (isDeviceSaved && isProtocolSaved) { if (isDeviceSaved && isProtocolSaved) {
alert('saved successfully'); alert('saved successfully');
@ -97,9 +149,11 @@ async function initializeApp() {
const deviceData = await loadDeviceConfig(); const deviceData = await loadDeviceConfig();
if (deviceData) { if (deviceData) {
deviceController.loadFromData(deviceData); deviceController.loadFromData(deviceData);
} else {
deviceController.loadDefaults();
} }
} catch (error) { } catch (error) {
console.error('Device load failed:', error); notifyLoadFailure('Device', error);
} }
try { try {
@ -108,7 +162,7 @@ async function initializeApp() {
protocolController.loadFromRegisterJson(protocolData); protocolController.loadFromRegisterJson(protocolData);
} }
} catch (error) { } catch (error) {
console.error('Protocol load failed:', error); notifyLoadFailure('Protocol', error);
} }
} }

Loading…
Cancel
Save