diff --git a/main.go b/main.go index 0e3086e..4687feb 100644 --- a/main.go +++ b/main.go @@ -19,6 +19,11 @@ const ( retryDelay = 10 * time.Second ) +type IPRecord struct { + Timestamp string `json:"timestamp"` + IPAddress string `json:"ip_address"` +} + func getPublicIP() (string, error) { var ip string var err error @@ -54,24 +59,31 @@ func fetchIP() (string, error) { return "", fmt.Errorf("IP address not found") } -func readHistory() ([]string, error) { +func readHistory() ([]IPRecord, error) { file, err := os.Open(ipHistoryPath) if os.IsNotExist(err) { - return []string{}, nil + return []IPRecord{}, nil } else if err != nil { return nil, err } defer file.Close() - var history []string + var history []IPRecord scanner := bufio.NewScanner(file) for scanner.Scan() { - history = append(history, scanner.Text()) + parts := strings.Split(scanner.Text(), " - ") + if len(parts) == 2 { + record := IPRecord{ + Timestamp: parts[0], + IPAddress: parts[1], + } + history = append(history, record) + } } return history, scanner.Err() } -func writeHistory(history []string) error { +func writeHistory(history []IPRecord) error { file, err := os.Create(ipHistoryPath) if err != nil { return err @@ -80,7 +92,7 @@ func writeHistory(history []string) error { writer := bufio.NewWriter(file) for _, entry := range history { - _, err := writer.WriteString(entry + "\n") + _, err := writer.WriteString(fmt.Sprintf("%s - %s\n", entry.Timestamp, entry.IPAddress)) if err != nil { return err } @@ -98,8 +110,8 @@ func trackIP(ipChan <-chan string) { } entry := fmt.Sprintf("%s - %s", time.Now().Format("2006-01-02 15:04:05 MST"), ip) - if len(history) == 0 || !strings.Contains(history[0], ip) { - history = append([]string{entry}, history...) + if len(history) == 0 || !strings.Contains(history[0].IPAddress, ip) { + history = append([]IPRecord{{Timestamp: time.Now().Format("2006-01-02 15:04:05 MST"), IPAddress: ip}}, history...) if err := writeHistory(history); err != nil { fmt.Println("Error writing IP history:", err) } diff --git a/web/index.html b/web/index.html index 6a3b13d..9282d00 100644 --- a/web/index.html +++ b/web/index.html @@ -6,9 +6,11 @@ IP History + + -

IP History

+

IP History

@@ -26,6 +28,5 @@
- diff --git a/web/script.js b/web/script.js index 2e0f41b..28ceb25 100644 --- a/web/script.js +++ b/web/script.js @@ -1,8 +1,11 @@ -let ipHistory = [], filteredHistory = [], currentPage = 1, entriesPerPage = 10; +let ipHistory = [], + filteredHistory = [], + currentPage = 1, + entriesPerPage = 10; $(document).ready(function() { $.getJSON('/history', function(data) { - ipHistory = data.map(entry => entry.split(" - ")); + ipHistory = data; filteredHistory = ipHistory; displayTable(); }).fail(function() { @@ -11,7 +14,7 @@ $(document).ready(function() { $('#searchBar').on('input', function() { const query = $(this).val().toLowerCase(); - filteredHistory = ipHistory.filter(row => row.some(cell => cell.toLowerCase().includes(query))); + filteredHistory = ipHistory.filter(entry => entry.timestamp.toLowerCase().includes(query) || entry.ip_address.toLowerCase().includes(query)); currentPage = 1; displayTable(); }); @@ -23,11 +26,10 @@ function displayTable() { const end = start + entriesPerPage; const currentEntries = filteredHistory.slice(start, end); - currentEntries.forEach(row => { + currentEntries.forEach(entry => { const tr = $(''); - row.forEach(cell => { - tr.append($('').text(cell)); - }); + tr.append($('').text(entry.timestamp)); + tr.append($('').text(entry.ip_address)); tbody.append(tr); }); updatePaginationButtons(); @@ -53,21 +55,27 @@ function prevPage() { } function sortTable() { - const th = $('#ipTable th').eq(0); - const isAscending = !th.hasClass('sort-asc'); + const isAscending = $('#ipTable th').eq(0).hasClass('sort-asc'); const orderModifier = isAscending ? 1 : -1; - filteredHistory.sort((a, b) => a[0].localeCompare(b[0]) * orderModifier); - th.toggleClass('sort-asc', isAscending).toggleClass('sort-desc', !isAscending); + filteredHistory.sort((a, b) => (a.timestamp.localeCompare(b.timestamp)) * orderModifier); + + $('#ipTable th').removeClass('sort-asc sort-desc'); + $('#ipTable th').eq(0).addClass(isAscending ? 'sort-desc' : 'sort-asc'); displayTable(); } function exportToCSV() { - const rows = [['Timestamp', 'IP Address'], ...filteredHistory]; + const rows = [ + ['Timestamp', 'IP Address'], ...filteredHistory.map(entry => [entry.timestamp, entry.ip_address]) + ]; const csvContent = "data:text/csv;charset=utf-8," + rows.map(e => e.join(",")).join("\n"); const encodedUri = encodeURI(csvContent); - const link = $('').attr({href: encodedUri, download: 'ip_history.csv'}); + const link = $('').attr({ + href: encodedUri, + download: 'ip_history.csv' + }); $('body').append(link); link[0].click(); diff --git a/web/style.css b/web/style.css index c5edc1f..16de239 100644 --- a/web/style.css +++ b/web/style.css @@ -12,6 +12,13 @@ h1 { text-align: center; margin: 20px 0; } +h1 a { + color: #007bff; + text-decoration: none; +} +h1 a:hover { + text-decoration: underline; +} .controls { width: 90%; max-width: 800px; @@ -20,14 +27,20 @@ h1 { align-items: center; margin: 20px 0; } +.export, .search-bar { + padding: 10px 20px; + border-radius: 5px; + border: 1px solid #444; + font-size: 16px; + line-height: 24px; +} .export { background-color: #007bff; color: #fff; - border: none; - padding: 10px 20px; cursor: pointer; - border-radius: 5px; flex-shrink: 0; + text-align: center; + border: none; } .export:hover { background-color: #0056b3; @@ -35,13 +48,13 @@ h1 { .search-bar { flex-grow: 1; margin-left: 20px; - padding: 10px; - border-radius: 5px; - border: 1px solid #444; background-color: #333; color: #fff; - font-size: 16px; - max-width: 100%; + border-color: #444; +} +.search-bar:focus { + outline: none; + border-color: #007bff; } table { width: 90%; @@ -62,6 +75,7 @@ th { cursor: pointer; background-color: #007bff; color: #fff; + border: none; } th.sort-asc::after { content: " \u2191";