Changed file structure #2
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
/tmp
|
/tmp
|
||||||
|
/uploads/*
|
1
api/Admin.go
Normal file
1
api/Admin.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package api
|
58
api/FileHandlers.go
Normal file
58
api/FileHandlers.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileData struct {
|
||||||
|
ImageNames []string
|
||||||
|
SpicyImageNames []string
|
||||||
|
AsciiFiles []AsciiEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
type AsciiEntry struct {
|
||||||
|
Name string
|
||||||
|
FontSize int
|
||||||
|
}
|
||||||
|
|
||||||
|
const staticDir = "static"
|
||||||
|
|
||||||
|
// move FileData and AsciiEntry here if you want, or leave in main.go
|
||||||
|
func FileHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
data := FileData{
|
||||||
|
ImageNames: []string{},
|
||||||
|
SpicyImageNames: []string{},
|
||||||
|
AsciiFiles: []AsciiEntry{},
|
||||||
|
}
|
||||||
|
|
||||||
|
files, _ := os.ReadDir(filepath.Join(staticDir, "images"))
|
||||||
|
for _, file := range files {
|
||||||
|
fileName := file.Name()
|
||||||
|
data.ImageNames = append(data.ImageNames, filepath.Join(staticDir, "images", fileName))
|
||||||
|
}
|
||||||
|
files, _ = os.ReadDir(filepath.Join("uploads"))
|
||||||
|
for _, file := range files {
|
||||||
|
fileName := file.Name()
|
||||||
|
data.ImageNames = append(data.ImageNames, filepath.Join("uploads", fileName))
|
||||||
|
}
|
||||||
|
|
||||||
|
files, _ = os.ReadDir(filepath.Join(staticDir, "spicy"))
|
||||||
|
for _, file := range files {
|
||||||
|
fileName := file.Name()
|
||||||
|
data.SpicyImageNames = append(data.SpicyImageNames, filepath.Join(staticDir, "spicy", fileName))
|
||||||
|
}
|
||||||
|
|
||||||
|
files, _ = os.ReadDir(filepath.Join(staticDir, "ascii_art"))
|
||||||
|
for _, file := range files {
|
||||||
|
fileName := file.Name()
|
||||||
|
data.AsciiFiles = append(data.AsciiFiles,
|
||||||
|
AsciiEntry{Name: filepath.Join(staticDir, "ascii_art", fileName), FontSize: 12},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(data)
|
||||||
|
}
|
36
api/UploadHandlers.go
Normal file
36
api/UploadHandlers.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != "POST" {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
file, header, err := r.FormFile("image") // "image" is the name of the file input
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Error retrieving file", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
dst, err := os.Create("./uploads/" + header.Filename)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Error creating file on server", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer dst.Close()
|
||||||
|
|
||||||
|
if _, err := io.Copy(dst, file); err != nil {
|
||||||
|
http.Error(w, "Error saving file", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprint(w, "<script>location.href = '/admin/'</script>")
|
||||||
|
fmt.Fprintf(w, "Image uploaded successfully: %s", header.Filename)
|
||||||
|
}
|
28
main.go
28
main.go
@@ -1,23 +1,24 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Advertisement_Panel/src"
|
"Advertisement_Panel/api"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
var templ *template.Template
|
var templates *template.Template
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
templ, _ = template.ParseGlob("templates/*.html")
|
templates, _ = template.ParseGlob("website/templates/*.html")
|
||||||
|
|
||||||
fmt.Print("Now running server!\n")
|
fmt.Print("Now running server!\n")
|
||||||
|
|
||||||
// Serves index
|
// Serves index
|
||||||
http.HandleFunc("/", index_handler)
|
http.HandleFunc("/", index_handler)
|
||||||
|
|
||||||
// Serves json for html to find file names
|
// Serves json for html to find file names
|
||||||
http.HandleFunc("/files", src.FileHandler)
|
http.HandleFunc("/files", api.FileHandler)
|
||||||
|
|
||||||
// Serves ascii page
|
// Serves ascii page
|
||||||
http.HandleFunc("/ascii", ascii_handler)
|
http.HandleFunc("/ascii", ascii_handler)
|
||||||
@@ -25,14 +26,29 @@ func main() {
|
|||||||
// Serves images
|
// Serves images
|
||||||
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
|
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
|
||||||
|
|
||||||
|
http.Handle("/uploads/", http.StripPrefix("/uploads/", http.FileServer(http.Dir("./uploads"))))
|
||||||
|
|
||||||
|
// Serves administration page
|
||||||
|
http.HandleFunc("/admin/", admin_handler)
|
||||||
|
|
||||||
|
// Handles image upload
|
||||||
|
http.HandleFunc("/upload", api.UploadHandler)
|
||||||
|
|
||||||
|
fmt.Print("Webserver running on http://localhost:8080\n")
|
||||||
|
|
||||||
// Serves what ever the user is requesting base on above urls
|
// Serves what ever the user is requesting base on above urls
|
||||||
http.ListenAndServe(":8080", nil)
|
http.ListenAndServe(":8080", nil)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func index_handler(w http.ResponseWriter, r *http.Request) {
|
func index_handler(w http.ResponseWriter, r *http.Request) {
|
||||||
templ.ExecuteTemplate(w, "images.html", nil)
|
templates.ExecuteTemplate(w, "images.html", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ascii_handler(w http.ResponseWriter, r *http.Request) {
|
func ascii_handler(w http.ResponseWriter, r *http.Request) {
|
||||||
templ.ExecuteTemplate(w, "ascii.html", nil)
|
templates.ExecuteTemplate(w, "ascii.html", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func admin_handler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
templates.ExecuteTemplate(w, "admin.html", nil)
|
||||||
}
|
}
|
||||||
|
@@ -1,69 +0,0 @@
|
|||||||
package src
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const staticDir = "static"
|
|
||||||
|
|
||||||
type FileData struct {
|
|
||||||
ImageNames []string
|
|
||||||
SpicyImageNames []string
|
|
||||||
AsciiFiles []AsciiEntry
|
|
||||||
}
|
|
||||||
|
|
||||||
type AsciiEntry struct {
|
|
||||||
Name string
|
|
||||||
FontSize int
|
|
||||||
}
|
|
||||||
|
|
||||||
// move FileData and AsciiEntry here if you want, or leave in main.go
|
|
||||||
func FileHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
data := FileData{
|
|
||||||
ImageNames: []string{},
|
|
||||||
SpicyImageNames: []string{},
|
|
||||||
AsciiFiles: []AsciiEntry{},
|
|
||||||
}
|
|
||||||
|
|
||||||
dirs, err := os.ReadDir(staticDir)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, dir := range dirs {
|
|
||||||
dirName := dir.Name()
|
|
||||||
|
|
||||||
if strings.EqualFold(dirName, "images") {
|
|
||||||
|
|
||||||
files, _ := os.ReadDir(filepath.Join(staticDir, dirName))
|
|
||||||
for _, file := range files {
|
|
||||||
fileName := file.Name()
|
|
||||||
data.ImageNames = append(data.ImageNames, filepath.Join(staticDir, dirName, fileName))
|
|
||||||
}
|
|
||||||
} else if strings.EqualFold(dirName, "spicy") {
|
|
||||||
|
|
||||||
files, _ := os.ReadDir(filepath.Join(staticDir, dirName))
|
|
||||||
for _, file := range files {
|
|
||||||
fileName := file.Name()
|
|
||||||
data.SpicyImageNames = append(data.SpicyImageNames, filepath.Join(staticDir, dirName, fileName))
|
|
||||||
}
|
|
||||||
} else if strings.EqualFold(dirName, "ascii_art") {
|
|
||||||
|
|
||||||
files, _ := os.ReadDir(filepath.Join(staticDir, dirName))
|
|
||||||
for _, file := range files {
|
|
||||||
fileName := file.Name()
|
|
||||||
data.AsciiFiles = append(data.AsciiFiles,
|
|
||||||
AsciiEntry{Name: filepath.Join(staticDir, dirName, fileName), FontSize: 12},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(data)
|
|
||||||
}
|
|
67
static/css/admin.css
Normal file
67
static/css/admin.css
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background: #101010;
|
||||||
|
color: #fff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background: #212121;
|
||||||
|
padding: 24px 32px;
|
||||||
|
border-radius: 8px;
|
||||||
|
max-width: 400px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||||
|
}
|
||||||
|
.active {
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
max-width: 400px;
|
||||||
|
background: #121212;
|
||||||
|
}
|
||||||
|
nav {
|
||||||
|
padding: 10px 18px;
|
||||||
|
border-radius: 8px;
|
||||||
|
width: 100%;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.08)
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
input[type="file"] {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
button[type="submit"] {
|
||||||
|
background: #007bff;
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
padding: 10px 18px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
button:hover {
|
||||||
|
background: #0056b3;
|
||||||
|
}
|
||||||
|
.preview {
|
||||||
|
margin-top: 16px;
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 200px;
|
||||||
|
display: none;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
22
static/css/global.css
Normal file
22
static/css/global.css
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: black;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color: white;
|
||||||
|
height: 100vh;
|
||||||
|
cursor: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
white-space: pre;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
71
static/js/admin.js
Normal file
71
static/js/admin.js
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
const imageInput = document.getElementById('imageInput');
|
||||||
|
const preview = document.getElementById('preview');
|
||||||
|
|
||||||
|
let currentFile = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
imageInput.addEventListener('change', function() {
|
||||||
|
currentFile = this.files[0];
|
||||||
|
if (currentFile) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = function(e) {
|
||||||
|
preview.src = e.target.result;
|
||||||
|
preview.style.display = 'block';
|
||||||
|
}
|
||||||
|
reader.readAsDataURL(currentFile);
|
||||||
|
} else {
|
||||||
|
preview.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('imageForm').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Add your upload logic here
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('image', currentFile);
|
||||||
|
if (!currentFile) {
|
||||||
|
alert('Please select an image to upload.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fetch('/upload', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
}).then(response => response.text())
|
||||||
|
.then(data => {
|
||||||
|
console.log(data);
|
||||||
|
alert('Image uploaded successfully!');
|
||||||
|
window.location.reload();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error:', error);
|
||||||
|
alert('Error uploading image.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function openTab(evt, tabNumber) {
|
||||||
|
// Declare all variables
|
||||||
|
var i, tabcontent, tablinks;
|
||||||
|
|
||||||
|
// Get all elements with class="tabcontent" and hide them
|
||||||
|
tabcontent = document.getElementsByClassName("tab-container");
|
||||||
|
for (i = 0; i < tabcontent.length; i++) {
|
||||||
|
tabcontent[i].style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all elements with class="tablinks" and remove the class "active"
|
||||||
|
tablinks = document.getElementsByClassName("tab-button");
|
||||||
|
for (i = 0; i < tablinks.length; i++) {
|
||||||
|
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the current tab, and add an "active" class to the button that opened the tab
|
||||||
|
console.log("tab-"+tabNumber);
|
||||||
|
let currentTab = document.getElementById('tab-'+(tabNumber))
|
||||||
|
if (currentTab) {
|
||||||
|
currentTab.style.display = "block";
|
||||||
|
} else throw new Error("Tab not found: " + tabNumber);
|
||||||
|
currentTab.style.display = "block";
|
||||||
|
evt.currentTarget.className += " active";
|
||||||
|
}
|
BIN
uploads/DSC_0094.jpg
Normal file
BIN
uploads/DSC_0094.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 MiB |
32
website/templates/admin.html
Normal file
32
website/templates/admin.html
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Admin</title>
|
||||||
|
<link rel="stylesheet" href="/static/css/admin.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main>
|
||||||
|
<nav>
|
||||||
|
<button class="tab-button" id="button-1" onclick="openTab(event, 1)">Image Upload</button>
|
||||||
|
<button class="tab-button" id="button-2" onclick="openTab(event, 2)">null</button>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="tab-container" id="tab-1">
|
||||||
|
<div class="container">
|
||||||
|
<h2>Add New Image</h2>
|
||||||
|
<form id="imageForm" enctype="multipart/form-data">
|
||||||
|
<label for="imageInput">Select Image:</label>
|
||||||
|
<input type="file" id="imageInput" name="image" accept="image/*" required><br>
|
||||||
|
<button type="submit" style="width: 100%;">Upload</button>
|
||||||
|
</form>
|
||||||
|
<img id="preview" class="preview" alt="Image Preview">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tab-container" id="tab-2">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<script src="/static/js/admin.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@@ -5,24 +5,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<link rel="icon" type="image/x-icon" href="/static/images/pvv_logo.png">
|
<link rel="icon" type="image/x-icon" href="/static/images/pvv_logo.png">
|
||||||
<title>ASCII</title>
|
<title>ASCII</title>
|
||||||
<style>
|
<link rel="stylesheet" href="/static/css/global.css">
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
background: black;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
color: white;
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
white-space: pre;
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 1.2;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
@@ -4,22 +4,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<link rel="icon" type="image/x-icon" href="/static/images/pvv_logo.png">
|
<link rel="icon" type="image/x-icon" href="/static/images/pvv_logo.png">
|
||||||
|
<link rel="stylesheet" href="/static/css/global.css">
|
||||||
<title>IMAGES</title>
|
<title>IMAGES</title>
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
background: black;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
max-width: 100%;
|
|
||||||
max-height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@@ -35,6 +21,9 @@
|
|||||||
index = (index + 1) % images.length;
|
index = (index + 1) % images.length;
|
||||||
document.getElementById("images").src = images[index];
|
document.getElementById("images").src = images[index];
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, images.length*2*1000);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
Reference in New Issue
Block a user