Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Lint Workflow For PRs #57

Merged
merged 1 commit into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ files/
.git
.gitignore

# prettier
.prettierignore

# ci
.github

# markdown
LICENSE.md
README.md
Expand Down
26 changes: 26 additions & 0 deletions .github/workflows/source-ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Source CI

on:
workflow_dispatch: # for manual runs
pull_request:
types: [ opened, synchronize ]

jobs:
build-and-test:
name: Run Lint
runs-on: ubuntu-latest

steps:
- name: Checkout Code
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 18

- name: Install Dependencies
run: npm install

- name: Run Prettier
run: npm run lint
4 changes: 4 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.json
**/*.md
**/*.css
**/*.yaml
4 changes: 2 additions & 2 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import express from 'express';
import Miscellaneous from './utils/misc.js';
import ProjectConfigs from './utils/data/configs.js';
import {logDebug, logTags} from './utils/log/logger.js';
import { logDebug, logTags } from './utils/log/logger.js';

// route imports
import logs from './routes/logs.js';
Expand Down Expand Up @@ -37,7 +37,7 @@ expressApp.use((req, res) => res.status(404).render('errors/404'));
logDebug(logTags.Express, 'Routes configured!');

// start the app with given port!
ProjectConfigs.ghosler().then(configs => {
ProjectConfigs.ghosler().then((configs) => {
expressApp.listen(configs.port);
logDebug(logTags.Express, 'App started successfully!');
logDebug(logTags.Express, '============================');
Expand Down
16 changes: 16 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@
"main": "app.js",
"type": "module",
"author": "@itznotabug",
"prettier": {
"tabWidth": 4,
"singleQuote": true
},
"scripts": {
"lint": "prettier . --check",
"format": "prettier . --write",
"dev": "nodemon -e js,ejs --ignore custom-template.ejs app.js",
"cleanstart": "npm run buildcss && npm run dev",
"buildcss": "npx tailwindcss -i ./public/styles/tailwind.css -o ./public/styles/style.css --minify"
Expand All @@ -28,9 +34,10 @@
"winston": "^3.13.0"
},
"devDependencies": {
"@types/cheerio": "^0.22.35",
"nodemon": "^3.1.0",
"prettier": "^3.3.0",
"tailwindcss": "^3.4.1",
"@types/cheerio": "^0.22.35",
"@types/express-fileupload": "^1.5.0"
}
}
4 changes: 2 additions & 2 deletions routes/analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ router.get('/details/:postId', async (req, res) => {
const postId = req.params.postId;
const post = await Files.get(postId);
const postSentiments = await new Ghost().postSentiments(postId);
res.render('dashboard/details', {post, postSentiments});
res.render('dashboard/details', { post, postSentiments });
});

export default router;
export default router;
12 changes: 7 additions & 5 deletions routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,26 @@ const router = express.Router();
router.get('/', async (_, res) => {
const configs = await ProjectConfigs.all();

if (configs.ghosler.auth.user === 'ghosler' &&
if (
configs.ghosler.auth.user === 'ghosler' &&
configs.ghosler.auth.pass === Miscellaneous.hash('admin')
) {
res.render('index', {
level: 'error',
message: 'Update your username and password.<br><br>Default - <br>Username: ghosler, Password: admin'
message:
'Update your username and password.<br><br>Default - <br>Username: ghosler, Password: admin',
});
} else if (configs.ghost.url === '' || configs.ghost.key === '') {
res.render('index', {
level: 'error',
message: 'Set up your Ghost Site Url & add an Admin API Key.'
message: 'Set up your Ghost Site Url & add an Admin API Key.',
});
} else if (configs.mail.length === 0) {
res.render('index', {
level: 'error',
message: 'Add email credentials to send newsletters.'
message: 'Add email credentials to send newsletters.',
});
} else res.render('index');
});

export default router;
export default router;
5 changes: 2 additions & 3 deletions routes/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Miscellaneous from '../utils/misc.js';
const router = express.Router();

router.get('/login', (req, res) => {
res.render('login', {redirect: req.query.redirect ?? ''});
res.render('login', { redirect: req.query.redirect ?? '' });
});

router.post('/login', async (req, res) => {
Expand All @@ -22,5 +22,4 @@ router.get('/logout', (req, res) => {
res.redirect('/');
});


export default router;
export default router;
2 changes: 1 addition & 1 deletion routes/logs.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ router.get('/clear/:type', async (req, res) => {
res.redirect(`/logs/${logType}`);
});

export default router;
export default router;
41 changes: 28 additions & 13 deletions routes/newsletters.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@ router.get('/:postId', async (req, res) => {
if (!postObject) {
return res.render('dashboard/newsletters', {
level: 'error',
message: 'Invalid Post Id!'
message: 'Invalid Post Id!',
});
}

if (postObject && postObject.stats && postObject.stats.newsletterStatus === 'Unsent') {
if (
postObject &&
postObject.stats &&
postObject.stats.newsletterStatus === 'Unsent'
) {
const newsletterItems = await new Ghost().newsletters();
delete newsletterItems.meta; // we don't need meta here.

Expand All @@ -28,12 +32,12 @@ router.get('/:postId', async (req, res) => {

res.render('dashboard/newsletters', {
post: postObject,
newsletters: newsletters
newsletters: newsletters,
});
} else {
res.render('dashboard/newsletters', {
level: 'error',
message: 'This post is already sent as a newsletter via email.'
message: 'This post is already sent as a newsletter via email.',
});
}
});
Expand All @@ -47,15 +51,15 @@ router.post('/send', async (req, res) => {
if (!postId || !newsletterId || !newsletterName) {
return res.render('dashboard/newsletters', {
level: 'error',
message: 'Post Id, Newsletter Id or Newsletter Name is missing!'
message: 'Post Id, Newsletter Id or Newsletter Name is missing!',
});
}

const postObject = await Files.get(postId);
if (!postObject) {
return res.render('dashboard/newsletters', {
level: 'error',
message: 'Invalid Post Id!'
message: 'Invalid Post Id!',
});
}

Expand All @@ -72,7 +76,12 @@ router.post('/send', async (req, res) => {
* 3. Post contains stats object &
* 4. Post's Stats newsletter status is 'Unsent'.
*/
if (post && post.content && post.stats && post.stats.newsletterStatus === 'Unsent') {
if (
post &&
post.content &&
post.stats &&
post.stats.newsletterStatus === 'Unsent'
) {
/**
* Mark the post's current status as 'Sending'
* This is done to prevent re-sending until Ghosler fetches members.
Expand All @@ -82,20 +91,26 @@ router.post('/send', async (req, res) => {
await post.update(true);

// send the newsletter as usual.
Newsletter.send(post, {id: newsletterId, name: newsletterName}).then();
Newsletter.send(post, {
id: newsletterId,
name: newsletterName,
}).then();

res.render('dashboard/newsletters', {
post: post,
level: 'success',
message: 'Newsletter will be sent shortly.'
message: 'Newsletter will be sent shortly.',
});

} else {
let message = 'This post is already sent as a newsletter via email.';
if (!post || !post.content || !post.stats) message = 'Post does not seem to be valid.';
if (!post || !post.content || !post.stats)
message = 'Post does not seem to be valid.';

res.render('dashboard/newsletters', {level: 'error', message: message});
res.render('dashboard/newsletters', {
level: 'error',
message: message,
});
}
});

export default router;
export default router;
3 changes: 1 addition & 2 deletions routes/password.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,4 @@ router.post('/', async (req, res) => {
res.render('dashboard/password', result);
});


export default router;
export default router;
2 changes: 1 addition & 1 deletion routes/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ router.get('/', async (_, res) => {
res.set('Content-Type', 'text/html').send(template.modifiedHtml);
});

export default router;
export default router;
28 changes: 20 additions & 8 deletions routes/published.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,28 @@ import Ghost from '../utils/api/ghost.js';
import Post from '../utils/models/post.js';
import Miscellaneous from '../utils/misc.js';
import Newsletter from '../utils/newsletter.js';
import {logDebug, logTags} from '../utils/log/logger.js';
import { logDebug, logTags } from '../utils/log/logger.js';

const router = express.Router();

router.post('/', async (req, res) => {
if (!req.body || !req.body.post || !req.body.post.current) {
return res.status(400).json({message: 'Post content seems to be missing!'});
return res
.status(400)
.json({ message: 'Post content seems to be missing!' });
}

// check if the request is authenticated.
const isSecure = await Miscellaneous.isPostSecure(req);
if (!isSecure) {
return res.status(401).json({message: 'Invalid Authorization.'});
return res.status(401).json({ message: 'Invalid Authorization.' });
}

// check if contains the ignore tag.
if (Post.containsIgnoreTag(req.body)) {
return res.status(200).json({message: 'Post contains `ghosler_ignore` tag, ignoring.'});
return res
.status(200)
.json({ message: 'Post contains `ghosler_ignore` tag, ignoring.' });
}

logDebug(logTags.Newsletter, 'Post received via webhook.');
Expand All @@ -30,16 +34,24 @@ router.post('/', async (req, res) => {
const created = await post.save(newslettersCount > 1);

if (!created) {
res.status(500).json({message: 'The post data could not be saved, or emails for this post have already been sent.'});
res.status(500).json({
message:
'The post data could not be saved, or emails for this post have already been sent.',
});
} else {
if (newslettersCount === 1) {
Newsletter.send(post).then();
res.status(200).json({message: 'Newsletter will be sent shortly.'});
res.status(200).json({
message: 'Newsletter will be sent shortly.',
});
} else {
// we probably have multiple active newsletters or none at all, so just save the post.
res.status(200).json({message: 'Multiple or No active Newsletters found, current Post saved for manual action.'});
res.status(200).json({
message:
'Multiple or No active Newsletters found, current Post saved for manual action.',
});
}
}
});

export default router;
export default router;
Loading