From 5ae4d6e7c4260aea0bd75adb39f1a9c79ccbacbc Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 22 Jun 2021 13:07:32 +0200 Subject: [PATCH] Read/write css file from app settings. Changed order of operations at app startup. Added nano to Dockerfile --- Dockerfile | 2 + Dockerfile.multiarch | 2 + client/.env | 2 +- client/public/flame.css | 0 client/public/index.html | 11 ++--- client/public/robots.txt | 3 +- client/src/components/Settings/Settings.tsx | 9 ++++ .../Settings/StyleSettings/StyleSettings.tsx | 44 +++++++++++++++++++ .../UI/Forms/InputGroup/InputGroup.module.css | 11 ++++- controllers/config.js | 29 ++++++++++++ db.js | 15 ++++--- models/associateModels.js | 8 ++-- routes/config.js | 7 +++ server.js | 28 ++++++------ utils/File.js | 25 +++++++++++ 15 files changed, 161 insertions(+), 35 deletions(-) create mode 100644 client/public/flame.css create mode 100644 client/src/components/Settings/StyleSettings/StyleSettings.tsx create mode 100644 utils/File.js diff --git a/Dockerfile b/Dockerfile index cd99f47..148d970 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,7 @@ FROM node:14-alpine +RUN apk update && apk add --no-cache nano + WORKDIR /app COPY package*.json ./ diff --git a/Dockerfile.multiarch b/Dockerfile.multiarch index 0cb1788..e0827af 100644 --- a/Dockerfile.multiarch +++ b/Dockerfile.multiarch @@ -1,5 +1,7 @@ FROM node:14-alpine +RUN apk update && apk add --no-cache nano + WORKDIR /app COPY package*.json ./ diff --git a/client/.env b/client/.env index 5a3822f..d53bf3c 100644 --- a/client/.env +++ b/client/.env @@ -1 +1 @@ -REACT_APP_VERSION=1.4.0 \ No newline at end of file +REACT_APP_VERSION=1.4.1 \ No newline at end of file diff --git a/client/public/flame.css b/client/public/flame.css new file mode 100644 index 0000000..e69de29 diff --git a/client/public/index.html b/client/public/index.html index 2ede77f..3f43c40 100644 --- a/client/public/index.html +++ b/client/public/index.html @@ -4,15 +4,10 @@ - - - - + + Flame @@ -21,4 +16,4 @@
- + \ No newline at end of file diff --git a/client/public/robots.txt b/client/public/robots.txt index e9e57dc..77470cb 100644 --- a/client/public/robots.txt +++ b/client/public/robots.txt @@ -1,3 +1,2 @@ -# https://www.robotstxt.org/robotstxt.html User-agent: * -Disallow: +Disallow: / \ No newline at end of file diff --git a/client/src/components/Settings/Settings.tsx b/client/src/components/Settings/Settings.tsx index 49b08bd..b1eb300 100644 --- a/client/src/components/Settings/Settings.tsx +++ b/client/src/components/Settings/Settings.tsx @@ -9,6 +9,7 @@ import Themer from '../Themer/Themer'; import WeatherSettings from './WeatherSettings/WeatherSettings'; import OtherSettings from './OtherSettings/OtherSettings'; import AppDetails from './AppDetails/AppDetails'; +import StyleSettings from './StyleSettings/StyleSettings'; const Settings = (): JSX.Element => { return ( @@ -40,6 +41,13 @@ const Settings = (): JSX.Element => { to='/settings/other'> Other + + CSS + { + diff --git a/client/src/components/Settings/StyleSettings/StyleSettings.tsx b/client/src/components/Settings/StyleSettings/StyleSettings.tsx new file mode 100644 index 0000000..f73ac1d --- /dev/null +++ b/client/src/components/Settings/StyleSettings/StyleSettings.tsx @@ -0,0 +1,44 @@ +import { useState, useEffect, ChangeEvent, FormEvent } from 'react'; +import axios from 'axios'; + +import InputGroup from '../../UI/Forms/InputGroup/InputGroup'; +import Button from '../../UI/Buttons/Button/Button'; +import { ApiResponse } from '../../../interfaces'; + +const StyleSettings = (): JSX.Element => { + const [customStyles, setCustomStyles] = useState(''); + + useEffect(() => { + axios.get>('/api/config/0/css') + .then(data => setCustomStyles(data.data.data)) + .catch(err => console.log(err)); + }, []) + + const inputChangeHandler = (e: ChangeEvent) => { + e.preventDefault(); + setCustomStyles(e.target.value); + } + + const formSubmitHandler = (e: FormEvent) => { + e.preventDefault(); + + axios.put>('/api/config/0/css', { styles: customStyles }); + } + + return ( +
formSubmitHandler(e)}> + + + + + +
+ ) +} + +export default StyleSettings; \ No newline at end of file diff --git a/client/src/components/UI/Forms/InputGroup/InputGroup.module.css b/client/src/components/UI/Forms/InputGroup/InputGroup.module.css index 6241764..93b74f1 100644 --- a/client/src/components/UI/Forms/InputGroup/InputGroup.module.css +++ b/client/src/components/UI/Forms/InputGroup/InputGroup.module.css @@ -4,12 +4,14 @@ .InputGroup label, .InputGroup span, -.InputGroup input { +.InputGroup input, +.InputGroup textarea { display: block; } .InputGroup input, -.InputGroup select { +.InputGroup select, +.InputGroup textarea { margin: 8px 0; width: 100%; border: none; @@ -30,4 +32,9 @@ .InputGroup label { color: var(--color-primary); +} + +.InputGroup textarea { + resize: none; + height: 50vh; } \ No newline at end of file diff --git a/controllers/config.js b/controllers/config.js index f8f3613..ef4f707 100644 --- a/controllers/config.js +++ b/controllers/config.js @@ -2,6 +2,8 @@ const asyncWrapper = require('../middleware/asyncWrapper'); const ErrorResponse = require('../utils/ErrorResponse'); const Config = require('../models/Config'); const { Op } = require('sequelize'); +const File = require('../utils/File'); +const { join } = require('path'); // @desc Insert new key:value pair // @route POST /api/config @@ -122,6 +124,33 @@ exports.deletePair = asyncWrapper(async (req, res, next) => { await pair.destroy(); + res.status(200).json({ + success: true, + data: {} + }) +}) + +// @desc Get custom CSS file +// @route GET /api/config/0/css +// @access Public +exports.getCss = asyncWrapper(async (req, res, next) => { + const file = new File(join(__dirname, '../public/flame.css')); + const content = file.read(); + + res.status(200).json({ + success: true, + data: content + }) +}) + + +// @desc Update custom CSS file +// @route PUT /api/config/0/css +// @access Public +exports.updateCss = asyncWrapper(async (req, res, next) => { + const file = new File(join(__dirname, '../public/flame.css')); + file.write(req.body.styles); + res.status(200).json({ success: true, data: {} diff --git a/db.js b/db.js index bc4c536..7728737 100644 --- a/db.js +++ b/db.js @@ -4,21 +4,26 @@ const sequelize = new Sequelize({ dialect: 'sqlite', storage: './data/db.sqlite', logging: false -}); +}) const connectDB = async () => { try { await sequelize.authenticate(); console.log('Connected to database'); - await sequelize.sync({ alter: true }); - console.log('All models were synced'); + const syncModels = true; + + if (syncModels) { + console.log('Starting model synchronization'); + await sequelize.sync({ alter: true }); + console.log('All models were synchronized'); + } } catch (error) { - console.error('Unable to connect to the database:', error); + throw new Error(`Unable to connect to the database: ${error.message}`); } } module.exports = { connectDB, sequelize -}; \ No newline at end of file +} \ No newline at end of file diff --git a/models/associateModels.js b/models/associateModels.js index 2457092..d1b86c1 100644 --- a/models/associateModels.js +++ b/models/associateModels.js @@ -2,12 +2,14 @@ const Category = require('./Category'); const Bookmark = require('./Bookmark'); const associateModels = () => { - // Category <> Bookmark Category.hasMany(Bookmark, { - as: 'bookmarks', + foreignKey: 'categoryId', + as: 'bookmarks' + }); + + Bookmark.belongsTo(Category, { foreignKey: 'categoryId' }); - Bookmark.belongsTo(Category, { foreignKey: 'categoryId' }); } module.exports = associateModels; \ No newline at end of file diff --git a/routes/config.js b/routes/config.js index caadbe5..eebf5dd 100644 --- a/routes/config.js +++ b/routes/config.js @@ -8,6 +8,8 @@ const { updateValue, updateValues, deletePair, + updateCss, + getCss, } = require('../controllers/config'); router @@ -22,4 +24,9 @@ router .put(updateValue) .delete(deletePair); +router + .route('/0/css') + .get(getCss) + .put(updateCss); + module.exports = router; \ No newline at end of file diff --git a/server.js b/server.js index 569b7ac..c15ebf0 100644 --- a/server.js +++ b/server.js @@ -10,20 +10,20 @@ const initConfig = require('./utils/initConfig'); const PORT = process.env.PORT || 5005; -connectDB() - .then(() => { - associateModels(); - initConfig(); - }); +(async () => { + await connectDB(); + await associateModels(); + await initConfig(); -// Create server for Express API and WebSockets -const server = http.createServer(); -server.on('request', api); + // Create server for Express API and WebSockets + const server = http.createServer(); + server.on('request', api); -// Register weatherSocket -const weatherSocket = new Socket(server); -Sockets.registerSocket('weather', weatherSocket); + // Register weatherSocket + const weatherSocket = new Socket(server); + Sockets.registerSocket('weather', weatherSocket); -server.listen(PORT, () => { - console.log(`Server is running on port ${PORT} in ${process.env.NODE_ENV} mode`); -}) \ No newline at end of file + server.listen(PORT, () => { + console.log(`Server is running on port ${PORT} in ${process.env.NODE_ENV} mode`); + }) +})(); \ No newline at end of file diff --git a/utils/File.js b/utils/File.js new file mode 100644 index 0000000..0b2fbdc --- /dev/null +++ b/utils/File.js @@ -0,0 +1,25 @@ +const fs = require('fs'); + +class File { + constructor(path) { + this.path = path; + this.content = ''; + } + + read() { + try { + const content = fs.readFileSync(this.path, { encoding: 'utf-8' }); + this.content = content; + return this.content; + } catch (err) { + return err.message; + } + } + + write(data) { + this.content = data; + fs.writeFileSync(this.path, this.content); + } +} + +module.exports = File; \ No newline at end of file