Added gallery database and refactored src-manager
This commit is contained in:
BIN
assets/databases/gallery.db
Normal file
BIN
assets/databases/gallery.db
Normal file
Binary file not shown.
@@ -22,7 +22,7 @@ npm run dev # JSファイル変更時に自動リロードが入る開発サー
|
|||||||
|
|
||||||
## データベース
|
## データベース
|
||||||
|
|
||||||
テーブル: news
|
### ファイル: news.db / テーブル: news
|
||||||
|
|
||||||
* id - PRIMARY KEY - 整数
|
* id - PRIMARY KEY - 整数
|
||||||
* date - Unix時間 - 整数
|
* date - Unix時間 - 整数
|
||||||
@@ -32,6 +32,12 @@ npm run dev # JSファイル変更時に自動リロードが入る開発サー
|
|||||||
* linkPath - ニュースリストで表示されるリンク先 - 文字列
|
* linkPath - ニュースリストで表示されるリンク先 - 文字列
|
||||||
* coverImagePath - ニュースリストで表示される画像へのパス - 文字列
|
* coverImagePath - ニュースリストで表示される画像へのパス - 文字列
|
||||||
|
|
||||||
|
### ファイル: gallery.db / テーブル: gallery
|
||||||
|
|
||||||
|
* id - PRIMARY KEY - 整数
|
||||||
|
* imagePath - 画像へのパス - 文字列
|
||||||
|
* caption - 画像の説明文 - 文字列
|
||||||
|
|
||||||
## API(RESTful)
|
## API(RESTful)
|
||||||
|
|
||||||
* `/api/news`
|
* `/api/news`
|
||||||
@@ -41,3 +47,10 @@ npm run dev # JSファイル変更時に自動リロードが入る開発サー
|
|||||||
* DELETE: Unix時間で特定されたニュースを削除する - `?target=<Unix時間>`
|
* DELETE: Unix時間で特定されたニュースを削除する - `?target=<Unix時間>`
|
||||||
* `/api/news-list`
|
* `/api/news-list`
|
||||||
* GET: 全ニュースの情報を取得する
|
* GET: 全ニュースの情報を取得する
|
||||||
|
|
||||||
|
* `/api/gallery-image`
|
||||||
|
* GET(`/`): IDで指定された画像へのパスと説明文を取得する - `?target=<ID>`
|
||||||
|
* GET(`/list`): 全画像の情報を取得する
|
||||||
|
* POST: 新しい画像の情報を追加する
|
||||||
|
* PUT: 画像の情報を更新する
|
||||||
|
* DELETE: IDで指定された画像の情報を削除する - `?target=<ID>`
|
||||||
133
src-manager/api/gallery-image.js
Normal file
133
src-manager/api/gallery-image.js
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
import express from 'express';
|
||||||
|
import sqlite3 from 'sqlite3';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import { asyncDatabaseRead, asyncDatabaseWrite } from '../utils/asyncDatabase.js';
|
||||||
|
|
||||||
|
const galleryImageAPI = express.Router();
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
const databasePath = path.join(__dirname, "../../assets/databases/gallery.db");
|
||||||
|
|
||||||
|
galleryImageAPI.get('/list', async (request, response) => {
|
||||||
|
const database = new sqlite3.Database(databasePath);
|
||||||
|
const sqlQuery = "SELECT * FROM gallery";
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await asyncDatabaseRead(database, sqlQuery, (rows) => {
|
||||||
|
let ret = "";
|
||||||
|
for (const entry of rows) {
|
||||||
|
ret = ret + "<tr>\n";
|
||||||
|
for (const data in entry) {
|
||||||
|
ret = ret + `<td>${entry[data]}</td>\n`;
|
||||||
|
}
|
||||||
|
ret = ret + `<td>\n
|
||||||
|
<button class='delete-button' hx-delete='/api/gallery-image?target=${entry["id"]}'>Delete</button>\n
|
||||||
|
<a href='/update-gallery-image.html?target=${entry["id"]}'><button class='edit-button' hx-confirm='unset'>Edit</button></a>\n
|
||||||
|
</td>\n</tr>\n`;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
|
||||||
|
database.close()
|
||||||
|
response.send(result);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
database.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
galleryImageAPI.get('/', async (request, response) => {
|
||||||
|
const database = new sqlite3.Database(databasePath);
|
||||||
|
|
||||||
|
const target = Number(request.query.target);
|
||||||
|
|
||||||
|
if (isNaN(target)) {
|
||||||
|
response.status(500).send("Query is not number");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sqlQuery = `SELECT * FROM gallery WHERE id = ${target}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await asyncDatabaseRead(database, sqlQuery, (rows) => {return rows[0]});
|
||||||
|
database.close();
|
||||||
|
response.send(result);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
database.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
galleryImageAPI.post('/', async (request, response) => {
|
||||||
|
const database = new sqlite3.Database(databasePath);
|
||||||
|
|
||||||
|
const imagePath = request.body.imagePath;
|
||||||
|
const caption = request.body.caption;
|
||||||
|
|
||||||
|
const sqlQuery = `INSERT INTO gallery (imagePath, caption) VALUES ("${imagePath}", "${caption}");`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await asyncDatabaseWrite(database, sqlQuery, () => {
|
||||||
|
console.log("Image added successfully.");
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
response.status(500).send(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
database.close();
|
||||||
|
response.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
galleryImageAPI.put('/', async (request, response) => {
|
||||||
|
const database = new sqlite3.Database(databasePath);
|
||||||
|
|
||||||
|
const target = Number(request.body.target);
|
||||||
|
|
||||||
|
if (isNaN(target)) {
|
||||||
|
response.status(500).send("Query is not number");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const imagePath = request.body.imagePath;
|
||||||
|
const caption = request.body.caption;
|
||||||
|
|
||||||
|
const sqlQuery = `UPDATE gallery SET imagePath = "${imagePath}", caption = "${caption}" WHERE id = ${target};`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await asyncDatabaseWrite(database, sqlQuery, () => {
|
||||||
|
console.log("Image updated successfully.");
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
response.status(500).send(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
database.close();
|
||||||
|
response.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
galleryImageAPI.delete('/', async (request, response) => {
|
||||||
|
const database = new sqlite3.Database(databasePath);
|
||||||
|
|
||||||
|
const target = Number(request.query.target);
|
||||||
|
|
||||||
|
if (isNaN(target)) {
|
||||||
|
response.status(404).send('No Entry Found!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sqlQuery = `DELETE FROM gallery WHERE id = ${target};`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await asyncDatabaseWrite(database, sqlQuery, () => {
|
||||||
|
console.log("Image deleted successfully.");
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
response.status(500).send(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
database.close();
|
||||||
|
response.status(200).send();
|
||||||
|
});
|
||||||
|
|
||||||
|
export default galleryImageAPI;
|
||||||
13
src-manager/api/index.js
Normal file
13
src-manager/api/index.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import express from 'express';
|
||||||
|
|
||||||
|
import newsAPI from './news.js';
|
||||||
|
import newsListAPI from './news-list.js';
|
||||||
|
import galleryImageAPI from './gallery-image.js';
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.use('/news', newsAPI);
|
||||||
|
router.use('/news-list', newsListAPI);
|
||||||
|
router.use('/gallery-image', galleryImageAPI);
|
||||||
|
|
||||||
|
export default router;
|
||||||
47
src-manager/api/news-list.js
Normal file
47
src-manager/api/news-list.js
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import express from 'express';
|
||||||
|
import sqlite3 from 'sqlite3';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import { asyncDatabaseRead } from '../utils/asyncDatabase.js';
|
||||||
|
|
||||||
|
const newsListAPI = express.Router();
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
const databasePath = path.join(__dirname, "../../assets/databases/news.db");
|
||||||
|
|
||||||
|
newsListAPI.get('/', async (request, response) => {
|
||||||
|
const database = new sqlite3.Database(databasePath);
|
||||||
|
const sqlQuery = `SELECT * FROM news ORDER BY date DESC;`;
|
||||||
|
try {
|
||||||
|
const result = await asyncDatabaseRead(database, sqlQuery, (rows) => {
|
||||||
|
let ret = "";
|
||||||
|
for (const entry of rows) {
|
||||||
|
ret = ret + "<tr>\n";
|
||||||
|
for (const data in entry) {
|
||||||
|
if (data == "article" || data == "coverImagePath" || data == "linkPath") continue;
|
||||||
|
if (data == "entryType") {
|
||||||
|
ret = ret + `<td>${entry[data] == 0 ? "Article" : "Tweet"}</td>\n`;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (data == "date") {
|
||||||
|
ret = ret + `<td>${new Date(entry[data]).toLocaleString()}</td>\n`;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ret = ret + `<td>${entry[data]}</td>\n`;
|
||||||
|
}
|
||||||
|
ret = ret + `<td>\n
|
||||||
|
<button class='delete-button' hx-delete='/api/news?target=${entry["date"]}'>Delete</button>\n
|
||||||
|
<a href='/update-news.html?target=${entry["date"]}'><button class='edit-button' hx-confirm='unset'>Edit</button></a>\n
|
||||||
|
</td>\n</tr>\n`;
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
});
|
||||||
|
database.close();
|
||||||
|
response.send(result);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
database.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default newsListAPI;
|
||||||
112
src-manager/api/news.js
Normal file
112
src-manager/api/news.js
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
import express from 'express';
|
||||||
|
import sqlite3 from 'sqlite3';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import { asyncDatabaseRead, asyncDatabaseWrite } from '../utils/asyncDatabase.js';
|
||||||
|
|
||||||
|
const newsAPI = express.Router();
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
const databasePath = path.join(__dirname, "../../assets/databases/news.db");
|
||||||
|
|
||||||
|
newsAPI.get('/', async (request, response) => {
|
||||||
|
const database = new sqlite3.Database(databasePath);
|
||||||
|
|
||||||
|
const target = Number(request.query.target);
|
||||||
|
|
||||||
|
if (isNaN(target)) {
|
||||||
|
response.status(500).send("Query is not number");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sqlQuery = `SELECT * FROM news WHERE date = ${target}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await asyncDatabaseRead(database, sqlQuery, (rows) => {return rows[0]});
|
||||||
|
database.close();
|
||||||
|
response.send(result);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
database.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
newsAPI.post('/', async (request, response) => {
|
||||||
|
const database = new sqlite3.Database(databasePath);
|
||||||
|
|
||||||
|
const currentDate = new Date();
|
||||||
|
const currentUnixTime = currentDate.valueOf();
|
||||||
|
const entryType = request.body.entryType;
|
||||||
|
const cardContent = request.body.cardContent;
|
||||||
|
const article = request.body.article;
|
||||||
|
const linkPath = entryType == 0 ? `/news/${request.body.linkPath}` : "";
|
||||||
|
const coverImagePath = request.body.coverImagePath;
|
||||||
|
|
||||||
|
const sqlQuery = `INSERT INTO news (date, entryType, cardContent, article, linkPath, coverImagePath) VALUES (${currentUnixTime}, ${entryType}, "${cardContent}", "${article}", "${linkPath}", "${coverImagePath}");`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await asyncDatabaseWrite(database, sqlQuery, () => {
|
||||||
|
console.log("News added successfully.");
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
response.status(500).send(err);
|
||||||
|
}
|
||||||
|
database.close();
|
||||||
|
response.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
newsAPI.put('/', async (request, response) => {
|
||||||
|
const database = new sqlite3.Database(databasePath);
|
||||||
|
|
||||||
|
const target = Number(request.body.target);
|
||||||
|
const entryType = Number(request.body.entryType);
|
||||||
|
const cardContent = request.body.cardContent;
|
||||||
|
const article = request.body.article;
|
||||||
|
const linkPath = entryType == 0 ? `/news/${request.body.linkPath}` : "";
|
||||||
|
const coverImagePath = request.body.coverImagePath;
|
||||||
|
|
||||||
|
if (isNaN(target)) {
|
||||||
|
response.status(500).send('Target is not number');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sqlQuery = `UPDATE news SET entryType = ${entryType}, cardContent = "${cardContent}", article = "${article}", linkPath = "${linkPath}", coverImagePath = "${coverImagePath}" WHERE date = ${target};`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await asyncDatabaseWrite(database, sqlQuery, () => {
|
||||||
|
console.log("News updated successfully.");
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
response.status(500).send(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
database.close();
|
||||||
|
response.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
newsAPI.delete('/', async (request, response) => {
|
||||||
|
const database = new sqlite3.Database(databasePath);
|
||||||
|
|
||||||
|
const target = Number(request.query.target);
|
||||||
|
|
||||||
|
if (isNaN(target)) {
|
||||||
|
response.status(404).send('No Entry Found!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sqlQuery = `DELETE FROM news WHERE date = ${target}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await asyncDatabaseWrite(database, sqlQuery, () => {
|
||||||
|
console.log("News deleted successfully.");
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
response.status(500).send(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
database.close();
|
||||||
|
|
||||||
|
response.status(200).send();
|
||||||
|
});
|
||||||
|
|
||||||
|
export default newsAPI;
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
import express from 'express';
|
import express from 'express';
|
||||||
import sqlite3 from 'sqlite3';
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import { asyncDatabaseRead, asyncDatabaseWrite } from './utils/asyncDatabase.js';
|
import router from './api/index.js';
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const port = 3001;
|
const port = 3001;
|
||||||
@@ -14,140 +13,7 @@ app.use(express.static(path.join(__dirname, 'pages')));
|
|||||||
app.use(express.static(path.join(__dirname, "../assets")));
|
app.use(express.static(path.join(__dirname, "../assets")));
|
||||||
app.use(express.static(path.join(__dirname, "../public")));
|
app.use(express.static(path.join(__dirname, "../public")));
|
||||||
|
|
||||||
app.get('/api/news-list', async (request, response) => {
|
app.use('/api', router);
|
||||||
const database = new sqlite3.Database(path.join(__dirname, "../assets/databases/news.db"));
|
|
||||||
const sqlQuery = `SELECT * FROM news ORDER BY date DESC;`;
|
|
||||||
try {
|
|
||||||
const result = await asyncDatabaseRead(database, sqlQuery, (rows) => {
|
|
||||||
let ret = "";
|
|
||||||
for (const entry of rows) {
|
|
||||||
ret = ret + "<tr>\n";
|
|
||||||
for (const data in entry) {
|
|
||||||
if (data == "article" || data == "coverImagePath" || data == "linkPath") continue;
|
|
||||||
if (data == "entryType") {
|
|
||||||
ret = ret + `<td>${entry[data] == 0 ? "Article" : "Tweet"}</td>\n`;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (data == "date") {
|
|
||||||
ret = ret + `<td>${new Date(entry[data]).toLocaleString()}</td>\n`;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ret = ret + `<td>${entry[data]}</td>\n`;
|
|
||||||
}
|
|
||||||
ret = ret + `<td>\n
|
|
||||||
<button class='delete-button' hx-delete='/api/news?target=${entry["date"]}'>Delete</button>\n
|
|
||||||
<a href='/update-news.html?target=${entry["date"]}'><button class='edit-button' hx-confirm='unset'>Edit</button></a>\n
|
|
||||||
</td>\n</tr>\n`;
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
});
|
|
||||||
database.close();
|
|
||||||
response.send(result);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
database.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/api/news', async (request, response) => {
|
|
||||||
const database = new sqlite3.Database(path.join(__dirname, "../assets/databases/news.db"));
|
|
||||||
|
|
||||||
const target = Number(request.query.target);
|
|
||||||
|
|
||||||
if (isNaN(target)) {
|
|
||||||
response.status(500).send("Query is not number");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sqlQuery = `SELECT * FROM news WHERE date = ${target}`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await asyncDatabaseRead(database, sqlQuery, (rows) => {return rows[0]});
|
|
||||||
database.close();
|
|
||||||
response.send(result);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
database.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/api/news', async (request, response) => {
|
|
||||||
const database = new sqlite3.Database(path.join(__dirname, "../assets/databases/news.db"));
|
|
||||||
|
|
||||||
const currentDate = new Date();
|
|
||||||
const currentUnixTime = currentDate.valueOf();
|
|
||||||
const entryType = request.body.entryType;
|
|
||||||
const cardContent = request.body.cardContent;
|
|
||||||
const article = request.body.article;
|
|
||||||
const linkPath = entryType == 0 ? `/news/${request.body.linkPath}` : "";
|
|
||||||
const coverImagePath = request.body.coverImagePath;
|
|
||||||
|
|
||||||
const sqlQuery = `INSERT INTO news (date, entryType, cardContent, article, linkPath, coverImagePath) VALUES (${currentUnixTime}, ${entryType}, "${cardContent}", "${article}", "${linkPath}", "${coverImagePath}");`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await asyncDatabaseWrite(database, sqlQuery, () => {
|
|
||||||
console.log("News added successfully.");
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
response.status(500).send(err);
|
|
||||||
}
|
|
||||||
database.close();
|
|
||||||
response.end();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.put('/api/news', async (request, response) => {
|
|
||||||
const database = new sqlite3.Database(path.join(__dirname, "../assets/databases/news.db"));
|
|
||||||
|
|
||||||
const target = Number(request.body.target);
|
|
||||||
const entryType = Number(request.body.entryType);
|
|
||||||
const cardContent = request.body.cardContent;
|
|
||||||
const article = request.body.article;
|
|
||||||
const linkPath = entryType == 0 ? `/news/${request.body.linkPath}` : "";
|
|
||||||
const coverImagePath = request.body.coverImagePath;
|
|
||||||
|
|
||||||
if (isNaN(target)) {
|
|
||||||
response.status(500).send('Target is not number');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sqlQuery = `UPDATE news SET entryType = ${entryType}, cardContent = "${cardContent}", article = "${article}", linkPath = "${linkPath}", coverImagePath = "${coverImagePath}" WHERE date = ${target};`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await asyncDatabaseWrite(database, sqlQuery, () => {
|
|
||||||
console.log("News updated successfully.");
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
response.status(500).send(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
database.close();
|
|
||||||
response.end();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.delete('/api/news', async (request, response) => {
|
|
||||||
const database = new sqlite3.Database(path.join(__dirname, "../assets/databases/news.db"));
|
|
||||||
|
|
||||||
const target = Number(request.query.target);
|
|
||||||
|
|
||||||
if (isNaN(target)) {
|
|
||||||
response.status(404).send('No Entry Found!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sqlQuery = `DELETE FROM news WHERE date = ${target}`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await asyncDatabaseWrite(database, sqlQuery, () => {
|
|
||||||
console.log("News deleted successfully.");
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
response.status(500).send(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
database.close();
|
|
||||||
|
|
||||||
response.status(200).send();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`Manager is now listening on port ${port}`);
|
console.log(`Manager is now listening on port ${port}`);
|
||||||
|
|||||||
30
src-manager/package-lock.json
generated
30
src-manager/package-lock.json
generated
@@ -18,9 +18,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-string-parser": {
|
"node_modules/@babel/helper-string-parser": {
|
||||||
"version": "7.24.8",
|
"version": "7.25.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz",
|
||||||
"integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==",
|
"integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -28,9 +28,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-validator-identifier": {
|
"node_modules/@babel/helper-validator-identifier": {
|
||||||
"version": "7.24.7",
|
"version": "7.25.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz",
|
||||||
"integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
|
"integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -38,13 +38,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/parser": {
|
"node_modules/@babel/parser": {
|
||||||
"version": "7.25.6",
|
"version": "7.25.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.7.tgz",
|
||||||
"integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==",
|
"integrity": "sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.25.6"
|
"@babel/types": "^7.25.7"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"parser": "bin/babel-parser.js"
|
"parser": "bin/babel-parser.js"
|
||||||
@@ -54,14 +54,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/types": {
|
"node_modules/@babel/types": {
|
||||||
"version": "7.25.6",
|
"version": "7.25.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.7.tgz",
|
||||||
"integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==",
|
"integrity": "sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-string-parser": "^7.24.8",
|
"@babel/helper-string-parser": "^7.25.7",
|
||||||
"@babel/helper-validator-identifier": "^7.24.7",
|
"@babel/helper-validator-identifier": "^7.25.7",
|
||||||
"to-fast-properties": "^2.0.0"
|
"to-fast-properties": "^2.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -27,9 +27,14 @@
|
|||||||
<li>
|
<li>
|
||||||
<a href="/new-news.html">New News</a>
|
<a href="/new-news.html">New News</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/new-gallery-image.html">New Gallery Image</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<button hx-get="/api/news-list" hx-trigger="click" hx-swap="innerHTML" hx-target="#entries">Refresh</button>
|
<h4>News</h4>
|
||||||
|
|
||||||
|
<button hx-get="/api/news-list" hx-trigger="click" hx-swap="innerHTML" hx-target="#news-entries">Refresh</button>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -40,11 +45,33 @@
|
|||||||
<td>Actions</td>
|
<td>Actions</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="entries" hx-confirm='Are you sure you want to delete this news?' hx-target="closest tr" hx-swap="outerHTML"></tbody>
|
<tbody id="news-entries" hx-confirm='Are you sure you want to delete this news?' hx-target="closest tr" hx-swap="outerHTML"></tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h4>Gallery Images</h4>
|
||||||
|
|
||||||
|
<button hx-get="/api/gallery-image/list" hx-trigger="click" hx-swap="innerHTML" hx-target="#image-entries">Refresh</button>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td>ID</td>
|
||||||
|
<td>Image Path</td>
|
||||||
|
<td>Caption</td>
|
||||||
|
<td>Actions</td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="image-entries" hx-confirm='Are you sure you want to delete this image? (Actual data will not deleted.)' hx-target="closest tr" hx-swap="outerHTML"></tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
htmx.ajax('GET', '/api/news-list', {target: '#entries', swap: 'innerHTML'});
|
const buttons = document.getElementsByTagName('button');
|
||||||
|
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
for (const btn of buttons) {
|
||||||
|
btn.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
51
src-manager/pages/new-gallery-image.html
Normal file
51
src-manager/pages/new-gallery-image.html
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Content Manager - new gallery image</title>
|
||||||
|
<script src="https://unpkg.com/htmx.org@2.0.2" integrity="sha384-Y7hw+L/jvKeWIRRkqWYfPcvVxHzVzn5REgzbawhxAuQGwX1XWe70vji+VSeHOThJ" crossorigin="anonymous"></script>
|
||||||
|
<style>
|
||||||
|
form fieldset {
|
||||||
|
display: grid;
|
||||||
|
grid-auto-flow: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
#new-news {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#preview {
|
||||||
|
border: black solid 1px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="new-gallery-image">
|
||||||
|
<h3></h3>
|
||||||
|
<form id="create-entry" hx-post="/api/gallery-image" hx-swap="none">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Create Entry</legend>
|
||||||
|
<label for="imagePath">Image Path:</label>
|
||||||
|
<input type="text" name="imagePath" id="imagePath">
|
||||||
|
<label for="caption">Caption of Image:</label>
|
||||||
|
<input type="text" name="caption" id="caption">
|
||||||
|
</fieldset>
|
||||||
|
<button id="submit-button" type="submit">Create Entry</button>
|
||||||
|
<a href="/index.html">
|
||||||
|
<button role="none" type="button">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const submitButton = document.getElementById('submit-button');
|
||||||
|
|
||||||
|
submitButton.addEventListener('click', () => {
|
||||||
|
window.location.href = "/index.html";
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Content Manager - new news</title>
|
<title>Content Manager - new news</title>
|
||||||
|
<link rel="stylesheet" href="/styles/markdown.css">
|
||||||
|
<link rel="stylesheet" href="/styles/color-pallet.css">
|
||||||
<script src="https://unpkg.com/htmx.org@2.0.2" integrity="sha384-Y7hw+L/jvKeWIRRkqWYfPcvVxHzVzn5REgzbawhxAuQGwX1XWe70vji+VSeHOThJ" crossorigin="anonymous"></script>
|
<script src="https://unpkg.com/htmx.org@2.0.2" integrity="sha384-Y7hw+L/jvKeWIRRkqWYfPcvVxHzVzn5REgzbawhxAuQGwX1XWe70vji+VSeHOThJ" crossorigin="anonymous"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||||
<style>
|
<style>
|
||||||
@@ -56,12 +58,12 @@
|
|||||||
<a href="/index.html"><button role="none" type="button">Cancel</button></a>
|
<a href="/index.html"><button role="none" type="button">Cancel</button></a>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div id="preview">
|
||||||
<h3>Preview</h3>
|
<h3>Preview</h3>
|
||||||
<h4>Card Content</h4>
|
<h4>Card Content</h4>
|
||||||
<div id="preview-card-content"></div>
|
<div id="preview-card-content"></div>
|
||||||
<h4>Article</h4>
|
<h4>Article</h4>
|
||||||
<div id="preview-article"></div>
|
<div id="preview-article" class="markdown"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
67
src-manager/pages/update-gallery-image.html
Normal file
67
src-manager/pages/update-gallery-image.html
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Content Manager - update gallery image</title>
|
||||||
|
<script src="https://unpkg.com/htmx.org@2.0.2" integrity="sha384-Y7hw+L/jvKeWIRRkqWYfPcvVxHzVzn5REgzbawhxAuQGwX1XWe70vji+VSeHOThJ" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
||||||
|
<style>
|
||||||
|
form fieldset {
|
||||||
|
display: grid;
|
||||||
|
grid-auto-flow: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
#new-news {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#preview {
|
||||||
|
border: black solid 1px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="new-gallery-image">
|
||||||
|
<h3></h3>
|
||||||
|
<form id="create-entry" hx-put="/api/gallery-image" hx-swap="none">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Create Entry</legend>
|
||||||
|
<label for="imagePath">Image Path:</label>
|
||||||
|
<input type="text" name="imagePath" id="imagePath">
|
||||||
|
<label for="caption">Caption of Image:</label>
|
||||||
|
<input type="text" name="caption" id="caption">
|
||||||
|
|
||||||
|
<input type="hidden" name="target" id="targetValue" value="test">
|
||||||
|
</fieldset>
|
||||||
|
<button id="submit-button" type="submit">Update Entry</button>
|
||||||
|
<a href="/index.html">
|
||||||
|
<button role="none" type="button">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const submitButton = document.getElementById('submit-button');
|
||||||
|
const imagePathInput = document.getElementById('imagePath');
|
||||||
|
const captionInput = document.getElementById('caption');
|
||||||
|
const targetInput = document.getElementById('targetValue');
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const targetEntry = urlParams.get('target');
|
||||||
|
|
||||||
|
axios.get('/api/gallery-image', {params: {target: targetEntry}})
|
||||||
|
.then((response) => {
|
||||||
|
targetInput.value = response.data.id;
|
||||||
|
imagePathInput.value = response.data.imagePath;
|
||||||
|
captionInput.value = response.data.caption;
|
||||||
|
})
|
||||||
|
.catch((err) => {console.error(err)});
|
||||||
|
|
||||||
|
submitButton.addEventListener('click', () => {
|
||||||
|
window.location.href = "/index.html";
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Content Manager - update news</title>
|
<title>Content Manager - update news</title>
|
||||||
|
<link rel="stylesheet" href="/styles/markdown.css">
|
||||||
|
<link rel="stylesheet" href="/styles/color-pallet.css">
|
||||||
<script src="https://unpkg.com/htmx.org@2.0.2" integrity="sha384-Y7hw+L/jvKeWIRRkqWYfPcvVxHzVzn5REgzbawhxAuQGwX1XWe70vji+VSeHOThJ" crossorigin="anonymous"></script>
|
<script src="https://unpkg.com/htmx.org@2.0.2" integrity="sha384-Y7hw+L/jvKeWIRRkqWYfPcvVxHzVzn5REgzbawhxAuQGwX1XWe70vji+VSeHOThJ" crossorigin="anonymous"></script>
|
||||||
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||||
@@ -59,12 +61,12 @@
|
|||||||
<a href="/index.html"><button role="none" type="button">Cancel</button></a>
|
<a href="/index.html"><button role="none" type="button">Cancel</button></a>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div id="preview">
|
||||||
<h3>Previews</h3>
|
<h3>Previews</h3>
|
||||||
<h4>Card Content</h4>
|
<h4>Card Content</h4>
|
||||||
<div id="preview-card-content"></div>
|
<div id="preview-card-content"></div>
|
||||||
<h4>Article</h4>
|
<h4>Article</h4>
|
||||||
<div id="preview-article"></div>
|
<div id="preview-article" class="markdown"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user