From 14ecd60a4d08a74b56fbfe3c0b0ef04a02b0de63 Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 3 Mar 2022 10:02:50 -0500 Subject: [PATCH] this app officially now does nothing and it's everything it's cracked up to be. --- app/controllers/admin.js | 3 - app/controllers/admin/newsletter.js | 123 -------- app/controllers/admin/page.js | 135 --------- app/controllers/admin/post.js | 152 ---------- app/controllers/comment.js | 158 ---------- app/controllers/content-report.js | 112 -------- app/controllers/home.js | 16 +- app/controllers/manifest.js | 2 +- app/controllers/newsletter.js | 104 ------- app/controllers/page.js | 74 ----- app/controllers/post.js | 218 -------------- app/models/category.js | 25 -- app/models/newsletter-recipient.js | 21 -- app/models/newsletter.js | 31 -- app/models/page.js | 29 -- app/models/post.js | 36 --- app/services/gab-tv.js | 60 ---- app/services/newsletter.js | 123 -------- app/services/page.js | 173 ----------- app/services/post.js | 183 ------------ app/views/admin/category/editor.pug | 17 -- app/views/admin/category/index.pug | 21 -- app/views/admin/newsletter/editor.pug | 66 ----- app/views/admin/newsletter/index.pug | 39 --- app/views/admin/page/editor.pug | 93 ------ app/views/admin/page/index.pug | 43 --- app/views/admin/post/editor.pug | 108 ------- app/views/admin/post/index.pug | 53 ---- app/views/category/components/list-item.pug | 6 - app/views/category/home.pug | 17 -- app/views/category/view.pug | 32 --- app/views/components/navbar.pug | 8 - app/views/components/off-canvas.pug | 5 - app/views/components/page-footer.pug | 69 +---- app/views/components/page-sidebar.pug | 41 +-- app/views/components/pwa-support.pug | 34 +-- app/views/index.pug | 36 +-- app/views/newsletter/index.pug | 15 - app/views/page/view.pug | 18 -- app/views/policy/privacy.md | 32 +-- app/views/policy/terms-of-service.md | 304 +------------------- app/views/post/components/featured-item.pug | 15 - app/views/post/components/list-item.pug | 24 -- app/views/post/view.pug | 66 ----- client/img/the-bobs.jpg | Bin 0 -> 115202 bytes lib/site-platform.js | 3 - 46 files changed, 33 insertions(+), 2910 deletions(-) delete mode 100644 app/controllers/admin/newsletter.js delete mode 100644 app/controllers/admin/page.js delete mode 100644 app/controllers/admin/post.js delete mode 100644 app/controllers/comment.js delete mode 100644 app/controllers/content-report.js delete mode 100644 app/controllers/newsletter.js delete mode 100644 app/controllers/page.js delete mode 100644 app/controllers/post.js delete mode 100644 app/models/category.js delete mode 100644 app/models/newsletter-recipient.js delete mode 100644 app/models/newsletter.js delete mode 100644 app/models/page.js delete mode 100644 app/models/post.js delete mode 100644 app/services/gab-tv.js delete mode 100644 app/services/newsletter.js delete mode 100644 app/services/page.js delete mode 100644 app/services/post.js delete mode 100644 app/views/admin/category/editor.pug delete mode 100644 app/views/admin/category/index.pug delete mode 100644 app/views/admin/newsletter/editor.pug delete mode 100644 app/views/admin/newsletter/index.pug delete mode 100644 app/views/admin/page/editor.pug delete mode 100644 app/views/admin/page/index.pug delete mode 100644 app/views/admin/post/editor.pug delete mode 100644 app/views/admin/post/index.pug delete mode 100644 app/views/category/components/list-item.pug delete mode 100644 app/views/category/home.pug delete mode 100644 app/views/category/view.pug delete mode 100644 app/views/newsletter/index.pug delete mode 100644 app/views/page/view.pug delete mode 100644 app/views/post/components/featured-item.pug delete mode 100644 app/views/post/components/list-item.pug delete mode 100644 app/views/post/view.pug create mode 100644 client/img/the-bobs.jpg diff --git a/app/controllers/admin.js b/app/controllers/admin.js index a2c696a..34054a6 100644 --- a/app/controllers/admin.js +++ b/app/controllers/admin.js @@ -48,9 +48,6 @@ class AdminController extends SiteController { router.use('/host',await this.loadChild(path.join(__dirname, 'admin', 'host'))); router.use('/job-queue', await this.loadChild(path.join(__dirname, 'admin', 'job-queue'))); router.use('/log', await this.loadChild(path.join(__dirname, 'admin', 'log'))); - router.use('/newsletter', await this.loadChild(path.join(__dirname, 'admin', 'newsletter'))); - router.use('/page', await this.loadChild(path.join(__dirname, 'admin', 'page'))); - router.use('/post', await this.loadChild(path.join(__dirname, 'admin', 'post'))); router.use('/settings', await this.loadChild(path.join(__dirname, 'admin', 'settings'))); router.use('/user', await this.loadChild(path.join(__dirname, 'admin', 'user'))); diff --git a/app/controllers/admin/newsletter.js b/app/controllers/admin/newsletter.js deleted file mode 100644 index 721c48b..0000000 --- a/app/controllers/admin/newsletter.js +++ /dev/null @@ -1,123 +0,0 @@ -// admin/newsletter.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const DTP_COMPONENT_NAME = 'admin:newsletter'; -const express = require('express'); - -const { SiteController, SiteError } = require('../../../lib/site-lib'); - -class NewsletterController extends SiteController { - - constructor (dtp) { - super(dtp, DTP_COMPONENT_NAME); - } - - async start ( ) { - const router = express.Router(); - router.use(async (req, res, next) => { - res.locals.currentView = 'admin'; - res.locals.adminView = 'newsletter'; - return next(); - }); - - router.param('newsletterId', this.populateNewsletterId.bind(this)); - - router.post('/:newsletterId', this.postUpdateNewsletter.bind(this)); - router.post('/', this.postCreateNewsletter.bind(this)); - - router.get('/compose', this.getComposer.bind(this)); - router.get('/:newsletterId', this.getComposer.bind(this)); - - router.get('/', this.getIndex.bind(this)); - - router.delete('/:newsletterId', this.deleteNewsletter.bind(this)); - - return router; - } - - async populateNewsletterId (req, res, next, newsletterId) { - const { newsletter: newsletterService } = this.dtp.services; - try { - res.locals.newsletter = await newsletterService.getById(newsletterId); - if (!res.locals.newsletter) { - throw new SiteError(404, 'Newsletter not found'); - } - return next(); - } catch (error) { - this.log.error('failed to populate newsletterId', { newsletterId, error }); - return next(error); - } - } - - async postUpdateNewsletter (req, res, next) { - const { newsletter: newsletterService } = this.dtp.services; - try { - await newsletterService.update(res.locals.newsletter, req.body); - res.redirect('/admin/newsletter'); - } catch (error) { - this.log.error('failed to update newsletter', { newletterId: res.locals.newsletter._id, error }); - return next(error); - } - } - - async postCreateNewsletter (req, res, next) { - const { newsletter: newsletterService } = this.dtp.services; - try { - await newsletterService.create(req.user, req.body); - res.redirect('/admin/newsletter'); - } catch (error) { - this.log.error('failed to create newsletter', { error }); - return next(error); - } - } - - async getComposer (req, res) { - res.render('admin/newsletter/editor'); - } - - async getIndex (req, res, next) { - const { newsletter: newsletterService } = this.dtp.services; - try { - res.locals.pagination = this.getPaginationParameters(req, 20); - res.locals.newsletters = await newsletterService.getNewsletters(res.locals.pagination, ['draft', 'published']); - res.render('admin/newsletter/index'); - } catch (error) { - return next(error); - } - } - - async deleteNewsletter (req, res) { - const { newsletter: newsletterService } = this.dtp.services; - try { - const displayList = this.createDisplayList('delete-newsletter'); - - await newsletterService.deleteNewsletter(res.locals.newsletter); - - displayList.removeElement(`li[data-newsletter-id="${res.locals.newsletter._id}"]`); - displayList.showNotification( - `Newsletter "${res.locals.newsletter.title}" deleted`, - 'success', - 'bottom-center', - 3000, - ); - res.status(200).json({ success: true, displayList }); - } catch (error) { - this.log.error('failed to delete newsletter', { - newsletterId: res.local.newsletter._id, - error, - }); - res.status(error.statusCode || 500).json({ - success: false, - message: error.message, - }); - } - } -} - -module.exports = async (dtp) => { - let controller = new NewsletterController(dtp); - return controller; -}; \ No newline at end of file diff --git a/app/controllers/admin/page.js b/app/controllers/admin/page.js deleted file mode 100644 index e3562e4..0000000 --- a/app/controllers/admin/page.js +++ /dev/null @@ -1,135 +0,0 @@ -// admin/page.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const DTP_COMPONENT_NAME = 'admin:page'; -const express = require('express'); - -const { SiteController, SiteError } = require('../../../lib/site-lib'); - -class PageController extends SiteController { - - constructor (dtp) { - super(dtp, DTP_COMPONENT_NAME); - } - - async start ( ) { - const router = express.Router(); - router.use(async (req, res, next) => { - res.locals.currentView = 'admin'; - res.locals.adminView = 'page'; - return next(); - }); - - router.param('pageId', this.populatePageId.bind(this)); - - router.post('/:pageId', this.pageUpdatePage.bind(this)); - router.post('/', this.pageCreatePage.bind(this)); - - router.get('/compose', this.getComposer.bind(this)); - router.get('/:pageId', this.getComposer.bind(this)); - - router.get('/', this.getIndex.bind(this)); - - router.delete('/:pageId', this.deletePage.bind(this)); - - return router; - } - - async populatePageId (req, res, next, pageId) { - const { page: pageService } = this.dtp.services; - try { - res.locals.page = await pageService.getById(pageId); - if (!res.locals.page) { - throw new SiteError(404, 'Page not found'); - } - return next(); - } catch (error) { - this.log.error('failed to populate pageId', { pageId, error }); - return next(error); - } - } - - async pageUpdatePage (req, res, next) { - const { page: pageService } = this.dtp.services; - try { - await pageService.update(res.locals.page, req.body); - res.redirect('/admin/page'); - } catch (error) { - this.log.error('failed to update page', { newletterId: res.locals.page._id, error }); - return next(error); - } - } - - async pageCreatePage (req, res, next) { - const { page: pageService } = this.dtp.services; - try { - await pageService.create(req.user, req.body); - res.redirect('/admin/page'); - } catch (error) { - this.log.error('failed to create page', { error }); - return next(error); - } - } - - async getComposer (req, res, next) { - const { page: pageService } = this.dtp.services; - try { - let excludedPages; - if (res.locals.page) { - excludedPages = [res.locals.page._id]; - } - res.locals.availablePages = await pageService.getAvailablePages(excludedPages); - res.render('admin/page/editor'); - } catch (error) { - this.log.error('failed to serve page editor', { error }); - return next(error); - } - } - - async getIndex (req, res, next) { - const { page: pageService } = this.dtp.services; - try { - res.locals.pagination = this.getPaginationParameters(req, 20); - res.locals.pages = await pageService.getPages(res.locals.pagination, ['draft', 'published', 'archived']); - res.render('admin/page/index'); - } catch (error) { - this.log.error('failed to fetch pages', { error }); - return next(error); - } - } - - async deletePage (req, res) { - const { page: pageService } = this.dtp.services; - try { - const displayList = this.createDisplayList('delete-page'); - - await pageService.deletePage(res.locals.page); - - displayList.removeElement(`li[data-page-id="${res.locals.page._id}"]`); - displayList.showNotification( - `Page "${res.locals.page.title}" deleted`, - 'success', - 'bottom-center', - 3000, - ); - res.status(200).json({ success: true, displayList }); - } catch (error) { - this.log.error('failed to delete page', { - pageId: res.local.page._id, - error, - }); - res.status(error.statusCode || 500).json({ - success: false, - message: error.message, - }); - } - } -} - -module.exports = async (dtp) => { - let controller = new PageController(dtp); - return controller; -}; \ No newline at end of file diff --git a/app/controllers/admin/post.js b/app/controllers/admin/post.js deleted file mode 100644 index 78f84f2..0000000 --- a/app/controllers/admin/post.js +++ /dev/null @@ -1,152 +0,0 @@ -// admin/post.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const DTP_COMPONENT_NAME = 'admin:post'; - -const express = require('express'); -const multer = require('multer'); - -const { SiteController, SiteError } = require('../../../lib/site-lib'); - -class PostController extends SiteController { - - constructor (dtp) { - super(dtp, DTP_COMPONENT_NAME); - } - - async start ( ) { - const upload = multer({ dest: `/tmp/${this.dtp.config.site.domainKey}/uploads/${DTP_COMPONENT_NAME}` }); - - const router = express.Router(); - router.use(async (req, res, next) => { - res.locals.currentView = 'admin'; - res.locals.adminView = 'post'; - return next(); - }); - - router.param('postId', this.populatePostId.bind(this)); - - router.post('/:postId/image', upload.single('imageFile'), this.postUpdateImage.bind(this)); - router.post('/:postId', this.postUpdatePost.bind(this)); - router.post('/', this.postCreatePost.bind(this)); - - router.get('/compose', this.getComposer.bind(this)); - router.get('/:postId', this.getComposer.bind(this)); - - router.get('/', this.getIndex.bind(this)); - - router.delete('/:postId', this.deletePost.bind(this)); - - return router; - } - - async populatePostId (req, res, next, postId) { - const { post: postService } = this.dtp.services; - try { - res.locals.post = await postService.getById(postId); - if (!res.locals.post) { - throw new SiteError(404, 'Post not found'); - } - return next(); - } catch (error) { - this.log.error('failed to populate postId', { postId, error }); - return next(error); - } - } - - async postUpdateImage (req, res) { - const { post: postService } = this.dtp.services; - try { - const displayList = this.createDisplayList('post-image'); - - await postService.updateImage(req.user, res.locals.post, req.file); - - displayList.showNotification( - 'Profile photo updated successfully.', - 'success', - 'bottom-center', - 2000, - ); - res.status(200).json({ success: true, displayList }); - } catch (error) { - this.log.error('failed to update feature image', { error }); - return res.status(error.statusCode || 500).json({ - success: false, - message: error.message, - }); - } - } - - async postUpdatePost (req, res, next) { - const { post: postService } = this.dtp.services; - try { - await postService.update(res.locals.post, req.body); - res.redirect('/admin/post'); - } catch (error) { - this.log.error('failed to update post', { newletterId: res.locals.post._id, error }); - return next(error); - } - } - - async postCreatePost (req, res, next) { - const { post: postService } = this.dtp.services; - try { - await postService.create(req.user, req.body); - res.redirect('/admin/post'); - } catch (error) { - this.log.error('failed to create post', { error }); - return next(error); - } - } - - async getComposer (req, res) { - res.render('admin/post/editor'); - } - - async getIndex (req, res, next) { - const { post: postService } = this.dtp.services; - try { - res.locals.pagination = this.getPaginationParameters(req, 20); - res.locals.posts = await postService.getAllPosts(res.locals.pagination); - res.render('admin/post/index'); - } catch (error) { - this.log.error('failed to fetch posts', { error }); - return next(error); - } - } - - async deletePost (req, res) { - const { post: postService } = this.dtp.services; - try { - const displayList = this.createDisplayList('delete-post'); - - await postService.deletePost(res.locals.post); - - displayList.removeElement(`li[data-post-id="${res.locals.post._id}"]`); - displayList.showNotification( - `Post "${res.locals.post.title}" deleted`, - 'success', - 'bottom-center', - 3000, - ); - res.status(200).json({ success: true, displayList }); - } catch (error) { - this.log.error('failed to delete post', { - postId: res.local.post._id, - error, - }); - res.status(error.statusCode || 500).json({ - success: false, - message: error.message, - }); - } - } -} - -module.exports = async (dtp) => { - let controller = new PostController(dtp); - return controller; -}; \ No newline at end of file diff --git a/app/controllers/comment.js b/app/controllers/comment.js deleted file mode 100644 index f93d309..0000000 --- a/app/controllers/comment.js +++ /dev/null @@ -1,158 +0,0 @@ -// comment.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const DTP_COMPONENT_NAME = 'comment'; - -const express = require('express'); -const numeral = require('numeral'); - -const { SiteController, SiteError } = require('../../lib/site-lib'); - -class CommentController extends SiteController { - - constructor (dtp) { - super(dtp, DTP_COMPONENT_NAME); - } - - async start ( ) { - const { dtp } = this; - const { limiter: limiterService, session: sessionService } = dtp.services; - - const authRequired = sessionService.authCheckMiddleware({ requiredLogin: true }); - - const router = express.Router(); - dtp.app.use('/comment', router); - - router.use(async (req, res, next) => { - res.locals.currentView = DTP_COMPONENT_NAME; - return next(); - }); - - router.param('commentId', this.populateCommentId.bind(this)); - - router.post('/:commentId/vote', authRequired, this.postVote.bind(this)); - - router.get('/:commentId/replies', this.getCommentReplies.bind(this)); - - router.delete('/:commentId', - authRequired, - limiterService.create(limiterService.config.comment.deleteComment), - this.deleteComment.bind(this), - ); - } - - async populateCommentId (req, res, next, commentId) { - const { comment: commentService } = this.dtp.services; - try { - res.locals.comment = await commentService.getById(commentId); - if (!res.locals.comment) { - return next(new SiteError(404, 'Comment not found')); - } - res.locals.post = res.locals.comment.resource; - return next(); - } catch (error) { - this.log.error('failed to populate commentId', { commentId, error }); - return next(error); - } - } - - async postVote (req, res) { - const { contentVote: contentVoteService } = this.dtp.services; - try { - const displayList = this.createDisplayList('comment-vote'); - const { message, stats } = await contentVoteService.recordVote(req.user, 'Comment', res.locals.comment, req.body.vote); - displayList.setTextContent( - `button[data-comment-id="${res.locals.comment._id}"][data-vote="up"] span.dtp-item-value`, - numeral(stats.upvoteCount).format(stats.upvoteCount > 1000 ? '0,0.0a' : '0,0'), - ); - displayList.setTextContent( - `button[data-comment-id="${res.locals.comment._id}"][data-vote="down"] span.dtp-item-value`, - numeral(stats.downvoteCount).format(stats.upvoteCount > 1000 ? '0,0.0a' : '0,0'), - ); - displayList.showNotification(message, 'success', 'bottom-center', 3000); - res.status(200).json({ success: true, displayList }); - } catch (error) { - this.log.error('failed to process comment vote', { error }); - return res.status(error.statusCode || 500).json({ - success: false, - message: error.message, - }); - } - } - - async getCommentReplies (req, res) { - const { comment: commentService } = this.dtp.services; - try { - const displayList = this.createDisplayList('get-replies'); - - if (req.query.buttonId) { - displayList.removeElement(`li.dtp-load-more[data-button-id="${req.query.buttonId}"]`); - } - - Object.assign(res.locals, req.app.locals); - - res.locals.countPerPage = parseInt(req.query.cpp || "20", 10); - if (res.locals.countPerPage < 1) { - res.locals.countPerPage = 1; - } - if (res.locals.countPerPage > 20) { - res.locals.countPerPage = 20; - } - - res.locals.pagination = this.getPaginationParameters(req, res.locals.countPerPage); - res.locals.comments = await commentService.getReplies(res.locals.comment, res.locals.pagination); - - const html = await commentService.renderTemplate('replyList', res.locals); - - const replyList = `ul.dtp-reply-list[data-comment-id="${res.locals.comment._id}"]`; - displayList.addElement(replyList, 'beforeEnd', html); - - const replyListContainer = `.dtp-reply-list-container[data-comment-id="${res.locals.comment._id}"]`; - displayList.removeAttribute(replyListContainer, 'hidden'); - - res.status(200).json({ success: true, displayList }); - } catch (error) { - this.log.error('failed to display comment replies', { error }); - res.status(error.statusCode || 500).json({ success: false, message: error.message }); - } - } - - async deleteComment (req, res) { - const { comment: commentService } = this.dtp.services; - try { - const displayList = this.createDisplayList('add-recipient'); - - await commentService.remove(res.locals.comment, 'removed'); - - let selector = `article[data-comment-id="${res.locals.comment._id}"] .comment-content`; - displayList.setTextContent(selector, 'Comment removed'); - - displayList.showNotification( - 'Comment removed successfully', - 'success', - 'bottom-center', - 5000, - ); - - res.status(200).json({ success: true, displayList }); - } catch (error) { - this.log.error('failed to remove comment', { error }); - return res.status(error.statusCode || 500).json({ - success: false, - message: error.message - }); - } - } -} - -module.exports = { - slug: 'comment', - name: 'comment', - create: async (dtp) => { - let controller = new CommentController(dtp); - return controller; - }, -}; \ No newline at end of file diff --git a/app/controllers/content-report.js b/app/controllers/content-report.js deleted file mode 100644 index b01b34c..0000000 --- a/app/controllers/content-report.js +++ /dev/null @@ -1,112 +0,0 @@ -// content-report.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const DTP_COMPONENT_NAME = 'content-report'; - -const express = require('express'); -const multer = require('multer'); - -const { SiteController } = require('../../lib/site-lib'); - -class ContentReportController extends SiteController { - - constructor (dtp) { - super(dtp, DTP_COMPONENT_NAME); - } - - async start ( ) { - const { dtp } = this; - const { limiter: limiterService, session: sessionService } = dtp.services; - - const authRequired = sessionService.authCheckMiddleware({ requiredLogin: true }); - const upload = multer({ dest: `/tmp/${this.dtp.config.site.domainKey}/uploads` }); - - const router = express.Router(); - dtp.app.use('/content-report', router); - - router.use(this.dtp.services.gabTV.channelMiddleware('mrjoeprich')); - router.use(async (req, res, next) => { - res.locals.currentView = 'content-report'; - return next(); - }); - - router.post('/comment/form', - limiterService.create(limiterService.config.contentReport.postCommentReportForm), - authRequired, - upload.none(), - this.postCommentReportForm.bind(this), - ); - router.post('/comment', - limiterService.create(limiterService.config.contentReport.postCommentReport), - authRequired, - upload.none(), - this.postCommentReport.bind(this), - ); - } - - async postCommentReportForm (req, res, next) { - const { comment: commentService } = this.dtp.services; - try { - res.locals.comment = await commentService.getById(req.body.commentId); - res.locals.params = req.body; - res.render('comment/components/report-form'); - } catch (error) { - return next(error); - } - } - - async postCommentReport (req, res) { - const { - contentReport: contentReportService, - comment: commentService, - user: userService, - } = this.dtp.services; - - const displayList = this.createDisplayList('add-recipient'); - - try { - res.locals.report = await contentReportService.create(req.user, { - resourceType: 'Comment', - resourceId: req.body.commentId, - category: req.body.category, - reason: req.body.reason, - }); - displayList.showNotification('Comment reported successfully', 'success', 'bottom-center', 5000); - - if (req.body.blockAuthor === 'on') { - const comment = await commentService.getById(req.body.commentId); - await userService.blockUser(req.user._id, comment.author._id || comment.author); - displayList.showNotification('Comment author blocked successfully', 'success', 'bottom-center', 5000); - } - - res.status(200).json({ success: true, displayList }); - } catch (error) { - this.log.error('failed to post comment report', { error }); - if (error.code === 11000) { - displayList.showNotification( - 'You already reported this comment', - 'primary', - 'bottom-center', - 5000, - ); - return res.status(200).json({ success: true, displayList }); - } - return res.status(error.statusCode || 500).json({ - success: false, - message: error.message, - }); - } - } -} - -module.exports = { - slug: 'content-report', - name: 'contentReport', - create: async (dtp) => { - let controller = new ContentReportController(dtp); - return controller; - }, -}; \ No newline at end of file diff --git a/app/controllers/home.js b/app/controllers/home.js index 94523d1..2e258e0 100644 --- a/app/controllers/home.js +++ b/app/controllers/home.js @@ -25,7 +25,6 @@ class HomeController extends SiteController { const router = express.Router(); dtp.app.use('/', router); - router.use(this.dtp.services.gabTV.channelMiddleware('mrjoeprich')); router.use(async (req, res, next) => { res.locals.currentView = 'home'; return next(); @@ -65,17 +64,8 @@ class HomeController extends SiteController { res.render('policy/view'); } - async getHome (req, res, next) { - const { post: postService } = this.dtp.services; - try { - res.locals.pagination = this.getPaginationParameters(req, 20); - res.locals.featuredPosts = await postService.getFeaturedPosts(3); - res.locals.posts = await postService.getPosts(res.locals.pagination); - - res.render('index'); - } catch (error) { - return next(error); - } + async getHome (req, res) { + res.render('index'); } } @@ -87,4 +77,4 @@ module.exports = { let controller = new HomeController(dtp); return controller; }, -}; +}; \ No newline at end of file diff --git a/app/controllers/manifest.js b/app/controllers/manifest.js index 5d2767a..c9edf1c 100644 --- a/app/controllers/manifest.js +++ b/app/controllers/manifest.js @@ -52,7 +52,7 @@ class ManifestController extends SiteController { [512, 384, 256, 192, 144, 96, 72, 48, 32, 16].forEach((size) => { manifest.icons.push({ - src: `/img/icon/icon-${size}x${size}.png`, + src: `/img/icon/${this.dtp.config.site.domainKey}/icon-${size}x${size}.png`, sizes: `${size}x${size}`, type: 'image/png' }); diff --git a/app/controllers/newsletter.js b/app/controllers/newsletter.js deleted file mode 100644 index 28bf9f9..0000000 --- a/app/controllers/newsletter.js +++ /dev/null @@ -1,104 +0,0 @@ -// newsletter.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const DTP_COMPONENT_NAME = 'newsletter'; - -const express = require('express'); -const multer = require('multer'); - -const { SiteController } = require('../../lib/site-lib'); - -class NewsletterController extends SiteController { - - constructor (dtp) { - super(dtp, DTP_COMPONENT_NAME); - } - - async start ( ) { - const { dtp } = this; - const { limiter: limiterService } = dtp.services; - - const upload = multer({ dest: `/tmp/${this.dtp.config.site.domainKey}/uploads/${DTP_COMPONENT_NAME}` }); - - const router = express.Router(); - dtp.app.use('/newsletter', router); - - router.use(async (req, res, next) => { - res.locals.currentView = DTP_COMPONENT_NAME; - return next(); - }); - - router.param('newsletterId', this.populateNewsletterId.bind(this)); - - router.post('/', upload.none(), this.postAddRecipient.bind(this)); - - router.get('/:newsletterId', - limiterService.create(limiterService.config.newsletter.getView), - this.getView.bind(this), - ); - - router.get('/', - limiterService.create(limiterService.config.newsletter.getIndex), - this.getIndex.bind(this), - ); - } - - async populateNewsletterId (req, res, next, newsletterId) { - const { newsletter: newsletterService } = this.dtp.services; - try { - res.locals.newsletter = await newsletterService.getById(newsletterId); - return next(); - } catch (error) { - this.log.error('failed to populate newsletterId', { newsletterId, error }); - return next(error); - } - } - - async postAddRecipient (req, res) { - const { newsletter: newsletterService } = this.dtp.services; - try { - const displayList = this.createDisplayList('add-recipient'); - await newsletterService.addRecipient(req.body.email); - displayList.showNotification( - 'You have been added to the newsletter. Please check your email and verify your email address.', - 'success', - 'bottom-center', - 10000, - ); - res.status(200).json({ success: true, displayList }); - } catch (error) { - this.log.error('failed to update account settings', { error }); - return res.status(error.statusCode || 500).json({ - success: false, - message: error.message, - }); - } - } - - async getView (req, res) { - res.render('newsletter/view'); - } - - async getIndex (req, res, next) { - const { newsletter: newsletterService } = this.dtp.services; - try { - res.locals.pagination = this.getPaginationParameters(req, 20); - res.locals.newsletters = await newsletterService.getNewsletters(res.locals.pagination); - res.render('newsletter/index'); - } catch (error) { - return next(error); - } - } -} - -module.exports = { - slug: 'newsletter', - name: 'newsletter', - create: async (dtp) => { - let controller = new NewsletterController(dtp); - return controller; - }, -}; diff --git a/app/controllers/page.js b/app/controllers/page.js deleted file mode 100644 index 7c236fb..0000000 --- a/app/controllers/page.js +++ /dev/null @@ -1,74 +0,0 @@ -// page.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const DTP_COMPONENT_NAME = 'page'; - -const express = require('express'); - -const { SiteController, SiteError } = require('../../lib/site-lib'); - -class PageController extends SiteController { - - constructor (dtp) { - super(dtp, DTP_COMPONENT_NAME); - } - - async start ( ) { - const { dtp } = this; - const { limiter: limiterService } = dtp.services; - - const router = express.Router(); - dtp.app.use('/page', router); - - router.use(this.dtp.services.gabTV.channelMiddleware('mrjoeprich')); - router.use(async (req, res, next) => { - res.locals.currentView = 'page'; - return next(); - }); - - router.param('pageSlug', this.populatePageSlug.bind(this)); - - router.get('/:pageSlug', - limiterService.create(limiterService.config.page.getView), - this.getView.bind(this), - ); - } - - async populatePageSlug (req, res, next, pageSlug) { - const { page: pageService } = this.dtp.services; - try { - res.locals.page = await pageService.getBySlug(pageSlug); - if (!res.locals.page) { - throw new SiteError(404, 'Page not found'); - } - return next(); - } catch (error) { - this.log.error('failed to populate pageSlug', { pageSlug, error }); - return next(error); - } - } - - async getView (req, res, next) { - const { resource: resourceService } = this.dtp.services; - try { - await resourceService.recordView(req, 'Page', res.locals.page._id); - res.locals.pageSlug = res.locals.page.slug; - res.render('page/view'); - } catch (error) { - this.log.error('failed to service page view', { pageId: res.locals.page._id, error }); - return next(error); - } - } -} - -module.exports = { - slug: 'page', - name: 'page', - create: async (dtp) => { - let controller = new PageController(dtp); - return controller; - }, -}; \ No newline at end of file diff --git a/app/controllers/post.js b/app/controllers/post.js deleted file mode 100644 index 546a33c..0000000 --- a/app/controllers/post.js +++ /dev/null @@ -1,218 +0,0 @@ -// post.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const DTP_COMPONENT_NAME = 'post'; - -const express = require('express'); -const multer = require('multer'); - -const { SiteController, SiteError } = require('../../lib/site-lib'); - -class PostController extends SiteController { - - constructor (dtp) { - super(dtp, DTP_COMPONENT_NAME); - } - - async start ( ) { - const { dtp } = this; - const { - comment: commentService, - limiter: limiterService, - session: sessionService, - } = dtp.services; - - const authRequired = sessionService.authCheckMiddleware({ requiredLogin: true }); - const upload = multer({ dest: `/tmp/dtp-sites/${this.dtp.config.site.domainKey}`}); - - const router = express.Router(); - dtp.app.use('/post', router); - - router.use(this.dtp.services.gabTV.channelMiddleware('mrjoeprich')); - router.use(async (req, res, next) => { - res.locals.currentView = 'home'; - return next(); - }); - - router.param('postSlug', this.populatePostSlug.bind(this)); - router.param('commentId', commentService.populateCommentId.bind(commentService)); - - router.post('/:postSlug/comment/:commentId/block-author', authRequired, upload.none(), this.postBlockCommentAuthor.bind(this)); - router.post('/:postSlug/comment', authRequired, upload.none(), this.postComment.bind(this)); - - router.get('/:postSlug/comment', - limiterService.create(limiterService.config.post.getComments), - this.getComments.bind(this), - ); - - router.get('/:postSlug', - limiterService.create(limiterService.config.post.getView), - this.getView.bind(this), - ); - - router.get('/', - limiterService.create(limiterService.config.post.getIndex), - this.getIndex.bind(this), - ); - } - - async populatePostSlug (req, res, next, postSlug) { - const { post: postService } = this.dtp.services; - try { - res.locals.post = await postService.getBySlug(postSlug); - if (!res.locals.post) { - throw new SiteError(404, 'Post not found'); - } - return next(); - } catch (error) { - this.log.error('failed to populate postSlug', { postSlug, error }); - return next(error); - } - } - - async postBlockCommentAuthor (req, res) { - const { user: userService } = this.dtp.services; - try { - const displayList = this.createDisplayList('add-recipient'); - await userService.blockUser(req.user._id, req.body.userId); - displayList.showNotification( - 'Comment author blocked', - 'success', - 'bottom-center', - 4000, - ); - res.status(200).json({ success: true, displayList }); - } catch (error) { - this.log.error('failed to report comment', { error }); - return res.status(error.statusCode || 500).json({ - success: false, - message: error.message, - }); - } - } - - async postComment (req, res) { - const { comment: commentService } = this.dtp.services; - try { - const displayList = this.createDisplayList('add-recipient'); - - res.locals.comment = await commentService.create(req.user, 'Post', res.locals.post, req.body); - - displayList.setInputValue('textarea#content', ''); - displayList.setTextContent('#comment-character-count', '0'); - - let viewModel = Object.assign({ }, req.app.locals); - viewModel = Object.assign(viewModel, res.locals); - - const html = await commentService.renderTemplate('comment', viewModel); - - if (req.body.replyTo) { - const replyListSelector = `.dtp-reply-list-container[data-comment-id="${req.body.replyTo}"]`; - displayList.addElement(replyListSelector, 'afterBegin', html); - displayList.removeAttribute(replyListSelector, 'hidden'); - } else { - displayList.addElement('ul#post-comment-list', 'afterBegin', html); - } - - displayList.showNotification( - 'Comment created', - 'success', - 'bottom-center', - 4000, - ); - res.status(200).json({ success: true, displayList }); - } catch (error) { - res.status(error.statusCode || 500).json({ success: false, message: error.message }); - } - } - - async getComments (req, res) { - const { comment: commentService } = this.dtp.services; - try { - const displayList = this.createDisplayList('add-recipient'); - - if (req.query.buttonId) { - displayList.removeElement(`li.dtp-load-more[data-button-id="${req.query.buttonId}"]`); - } - - Object.assign(res.locals, req.app.locals); - - res.locals.countPerPage = parseInt(req.query.cpp || "20", 10); - if (res.locals.countPerPage < 1) { - res.locals.countPerPage = 1; - } - if (res.locals.countPerPage > 20) { - res.locals.countPerPage = 20; - } - - res.locals.pagination = this.getPaginationParameters(req, res.locals.countPerPage); - - res.locals.comments = await commentService.getForResource( - res.locals.post, - ['published', 'mod-warn', 'mod-removed', 'removed'], - res.locals.pagination, - ); - - const html = await commentService.renderTemplate('commentList', res.locals); - - const replyList = `ul#post-comment-list`; - displayList.addElement(replyList, 'beforeEnd', html); - - res.status(200).json({ success: true, displayList }); - } catch (error) { - this.log.error('failed to fetch more commnets', { postId: res.locals.post._id, error }); - return res.status(error.statusCode || 500).json({ - success: false, - message: error.message, - }); - } - } - - async getView (req, res, next) { - const { comment: commentService, resource: resourceService } = this.dtp.services; - try { - await resourceService.recordView(req, 'Post', res.locals.post._id); - - res.locals.countPerPage = 20; - res.locals.pagination = this.getPaginationParameters(req, res.locals.countPerPage); - - if (req.query.comment) { - res.locals.featuredComment = await commentService.getById(req.query.comment); - } - - res.locals.comments = await commentService.getForResource( - res.locals.post, - ['published', 'mod-warn', 'mod-removed', 'removed'], - res.locals.pagination, - ); - - res.render('post/view'); - } catch (error) { - this.log.error('failed to service post view', { postId: res.locals.post._id, error }); - return next(error); - } - } - - async getIndex (req, res, next) { - const { post: postService } = this.dtp.services; - try { - res.locals.pagination = this.getPaginationParameters(req, 20); - res.locals.posts = await postService.getPosts(res.locals.pagination); - res.render('post/index'); - } catch (error) { - return next(error); - } - } -} - -module.exports = { - slug: 'post', - name: 'post', - create: async (dtp) => { - let controller = new PostController(dtp); - return controller; - }, -}; \ No newline at end of file diff --git a/app/models/category.js b/app/models/category.js deleted file mode 100644 index 3466418..0000000 --- a/app/models/category.js +++ /dev/null @@ -1,25 +0,0 @@ -// category.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const mongoose = require('mongoose'); - -const Schema = mongoose.Schema; - -const CategorySchema = new Schema({ - name: { type: String }, - slug: { type: String, lowercase: true, required: true, index: 1 }, - description: { type: String }, - images: { - header: { type: Schema.ObjectId }, - icon: { type: Schema.ObjectId }, - }, - stats: { - articleCount: { type: Number, default: 0, required: true }, - articleViewCount: { type: Number, default: 0, required: true }, - }, -}); - -module.exports = mongoose.model('Category', CategorySchema); \ No newline at end of file diff --git a/app/models/newsletter-recipient.js b/app/models/newsletter-recipient.js deleted file mode 100644 index 8347b0c..0000000 --- a/app/models/newsletter-recipient.js +++ /dev/null @@ -1,21 +0,0 @@ -// newsletter-recipient.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const mongoose = require('mongoose'); -const Schema = mongoose.Schema; - -const NewsletterRecipientSchema = new Schema({ - created: { type: Date, default: Date.now, required: true, index: 1 }, - address: { type: String, required: true }, - address_lc: { type: String, required: true, lowercase: true, unique: true, index: 1 }, - flags: { - isVerified: { type: Boolean, default: false, required: true, index: 1 }, - isOptIn: { type: Boolean, default: false, required: true, index: 1 }, - isRejected: { type: Boolean, default: false, required: true, index: 1 }, - }, -}); - -module.exports = mongoose.model('NewsletterRecipient', NewsletterRecipientSchema); \ No newline at end of file diff --git a/app/models/newsletter.js b/app/models/newsletter.js deleted file mode 100644 index 673a8ea..0000000 --- a/app/models/newsletter.js +++ /dev/null @@ -1,31 +0,0 @@ -// newsletter.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const mongoose = require('mongoose'); - -const Schema = mongoose.Schema; - -const NEWSLETTER_STATUS_LIST = ['draft', 'published', 'archived']; - -const NewsletterSchema = new Schema({ - created: { type: Date, default: Date.now, required: true, index: -1 }, - author: { type: Schema.ObjectId, required: true, index: 1, ref: 'User' }, - title: { type: String, required: true }, - summary: { type: String }, - content: { - html: { type: String, required: true, select: false, }, - text: { type: String, required: true, select: false, }, - }, - status: { - type: String, - enum: NEWSLETTER_STATUS_LIST, - default: 'draft', - required: true, - index: true, - }, -}); - -module.exports = mongoose.model('Newsletter', NewsletterSchema); \ No newline at end of file diff --git a/app/models/page.js b/app/models/page.js deleted file mode 100644 index 15d2e85..0000000 --- a/app/models/page.js +++ /dev/null @@ -1,29 +0,0 @@ -// page.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const mongoose = require('mongoose'); -const Schema = mongoose.Schema; - -const PAGE_STATUS_LIST = ['draft','published','archived']; - -const PageSchema = new Schema({ - title: { type: String, required: true }, - slug: { type: String, required: true, lowercase: true, unique: true }, - image: { - header: { type: Schema.ObjectId, ref: 'Image' }, - icon: { type: Schema.ObjectId, ref: 'Image' }, - }, - content: { type: String, required: true, select: false }, - status: { type: String, enum: PAGE_STATUS_LIST, default: 'draft', index: true }, - menu: { - icon: { type: String, required: true }, - label: { type: String, required: true }, - order: { type: Number, default: 0, required: true }, - parent: { type: Schema.ObjectId, index: 1, ref: 'Page' }, - }, -}); - -module.exports = mongoose.model('Page', PageSchema); \ No newline at end of file diff --git a/app/models/post.js b/app/models/post.js deleted file mode 100644 index 3529c15..0000000 --- a/app/models/post.js +++ /dev/null @@ -1,36 +0,0 @@ -// post.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const path = require('path'); -const mongoose = require('mongoose'); - -const Schema = mongoose.Schema; - -const { - ResourceStats, - ResourceStatsDefaults, -} = require(path.join(__dirname, 'lib', 'resource-stats.js')); - -const POST_STATUS_LIST = ['draft','published','archived']; - -const PostSchema = new Schema({ - created: { type: Date, default: Date.now, required: true, index: -1 }, - updated: { type: Date }, - author: { type: Schema.ObjectId, required: true, index: 1, ref: 'User' }, - image: { type: Schema.ObjectId, ref: 'Image' }, - title: { type: String, required: true }, - slug: { type: String, required: true, lowercase: true, unique: true }, - summary: { type: String, required: true }, - content: { type: String, required: true, select: false }, - status: { type: String, enum: POST_STATUS_LIST, default: 'draft', index: true }, - stats: { type: ResourceStats, default: ResourceStatsDefaults, required: true }, - flags: { - enableComments: { type: Boolean, default: true, index: true }, - isFeatured: { type: Boolean, default: false, index: true }, - }, -}); - -module.exports = mongoose.model('Post', PostSchema); \ No newline at end of file diff --git a/app/services/gab-tv.js b/app/services/gab-tv.js deleted file mode 100644 index 1a9032f..0000000 --- a/app/services/gab-tv.js +++ /dev/null @@ -1,60 +0,0 @@ -// gab-tv.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const fetch = require('node-fetch'); // jshint ignore:line - -const CACHE_DURATION = 60 * 5; - -const { SiteService } = require('../../lib/site-lib'); - -class GabTVService extends SiteService { - - constructor (dtp) { - super(dtp, module.exports); - } - - channelMiddleware (channelSlug) { - return async (req, res, next) => { - try { - res.locals.gabTvChannel = await this.getChannelEpisodes(channelSlug, { allowCache: true }); - return next(); - } catch (error) { - this.log.error('failed to populdate Gab TV channel', { channelSlug, error }); - return next(); - } - }; - } - - async getChannelEpisodes (channelSlug, options) { - const { cache: cacheService } = this.dtp.services; - const cacheKey = `gabtv:ch:${channelSlug}`; - - options = Object.assign({ - allowCache: true, - }, options); - - let json; - if (options.allowCache) { - json = await cacheService.getObject(cacheKey); - if (json) { - return json; - } - } - - const response = await fetch(`https://tv.gab.com/channel/${channelSlug}/feed/json`); - json = await response.json(); - - await cacheService.setObjectEx(cacheKey, CACHE_DURATION, json); - - return json; - } -} - -module.exports = { - slug: 'gab-tv', - name: 'gabTV', - create: (dtp) => { return new GabTVService(dtp); }, -}; \ No newline at end of file diff --git a/app/services/newsletter.js b/app/services/newsletter.js deleted file mode 100644 index 270032a..0000000 --- a/app/services/newsletter.js +++ /dev/null @@ -1,123 +0,0 @@ -// newsletter.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const striptags = require('striptags'); - -const { SiteService } = require('../../lib/site-lib'); - -const mongoose = require('mongoose'); - -const Newsletter = mongoose.model('Newsletter'); -const NewsletterRecipient = mongoose.model('NewsletterRecipient'); - -class NewsletterService extends SiteService { - - constructor (dtp) { - super(dtp, module.exports); - - this.populateNewsletter = [ - { - path: 'author', - select: '_id username username_lc displayName picture', - }, - ]; - } - - async create (author, newsletterDefinition) { - const NOW = new Date(); - - const newsletter = new Newsletter(); - newsletter.created = NOW; - newsletter.author = author._id; - newsletter.title = striptags(newsletterDefinition.title.trim()); - newsletter.summary = striptags(newsletterDefinition.summary.trim()); - newsletter.content.html = newsletterDefinition['content.html'].trim(); - newsletter.content.text = striptags(newsletterDefinition['content.text'].trim()); - newsletter.status = 'draft'; - - await newsletter.save(); - - return newsletter.toObject(); - } - - async update (newsletter, newsletterDefinition) { - const updateOp = { $set: { } }; - - if (newsletterDefinition.title) { - updateOp.$set.title = striptags(newsletterDefinition.title.trim()); - } - if (newsletterDefinition.summary) { - updateOp.$set.summary = striptags(newsletterDefinition.summary.trim()); - } - if (newsletterDefinition['content.html']) { - updateOp.$set['content.html'] = newsletterDefinition['content.html'].trim(); - } - if (newsletterDefinition['content.text']) { - updateOp.$set['content.text'] = striptags(newsletterDefinition['content.text'].trim()); - } - if (newsletterDefinition.status) { - updateOp.$set.status = striptags(newsletterDefinition.status.trim()); - } - - if (Object.keys(updateOp.$set).length === 0) { - return; // no update to perform - } - - await Newsletter.updateOne( - { _id: newsletter._id }, - updateOp, - { upsert: true }, - ); - } - - async getNewsletters (pagination, status = ['published']) { - if (!Array.isArray(status)) { - status = [status]; - } - const newsletters = await Newsletter - .find({ status: { $in: status } }) - .sort({ created: -1 }) - .skip(pagination.skip) - .limit(pagination.cpp) - .lean(); - return newsletters; - } - - async getById (newsletterId) { - const newsletter = await Newsletter - .findById(newsletterId) - .select('+content.html +content.text') - .populate(this.populateNewsletter) - .lean(); - return newsletter; - } - - async addRecipient (emailAddress) { - const { email: emailService } = this.dtp.services; - const NOW = new Date(); - - await emailService.checkEmailAddress(emailAddress); - - const recipient = new NewsletterRecipient(); - recipient.created = NOW; - recipient.address = striptags(emailAddress.trim()); - recipient.address_lc = recipient.address.toLowerCase(); - await recipient.save(); - - return recipient.toObject(); - } - - async deleteNewsletter (newsletter) { - this.log.info('deleting newsletter', { newsletterId: newsletter._id }); - await Newsletter.deleteOne({ _id: newsletter._id }); - } -} - -module.exports = { - slug: 'newsletter', - name: 'newsletter', - create: (dtp) => { return new NewsletterService(dtp); }, -}; \ No newline at end of file diff --git a/app/services/page.js b/app/services/page.js deleted file mode 100644 index a13bd60..0000000 --- a/app/services/page.js +++ /dev/null @@ -1,173 +0,0 @@ -// page.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const striptags = require('striptags'); -const slug = require('slug'); - -const { SiteService } = require('../../lib/site-lib'); - -const mongoose = require('mongoose'); -const ObjectId = mongoose.Types.ObjectId; - -const Page = mongoose.model('Page'); - -class PageService extends SiteService { - - constructor (dtp) { - super(dtp, module.exports); - } - - async menuMiddleware (req, res, next) { - try { - const pages = await Page - .find({ parent: { $exists: false } }) - .select('slug menu') - .lean(); - - res.locals.mainMenu = pages - .filter((page) => !page.parent) - .map((page) => { - return { - url: `/page/${page.slug}`, - slug: page.slug, - icon: page.menu.icon, - label: page.menu.label, - order: page.menu.order, - }; - }) - .sort((a, b) => { - return a.order < b.order; - }); - return next(); - } catch (error) { - this.log.error('failed to build page menu', { error }); - return next(); - } - } - - async create (author, pageDefinition) { - const page = new Page(); - page.title = striptags(pageDefinition.title.trim()); - page.slug = this.createPageSlug(page._id, page.title); - page.content = pageDefinition.content.trim(); - page.status = pageDefinition.status || 'draft'; - - page.menu = { - icon: striptags((pageDefinition.menuIcon || 'fa-slash').trim().toLowerCase()), - label: striptags((pageDefinition.menuLabel || page.title.slice(0, 10))), - order: parseInt(pageDefinition.menuOrder || '0', 10), - }; - - if (pageDefinition.parentPageId && (pageDefinition.parentPageId !== 'none')) { - page.menu.parent = pageDefinition.parentPageId; - } - await page.save(); - - return page.toObject(); - } - - async update (page, pageDefinition) { - const NOW = new Date(); - const updateOp = { - $set: { - updated: NOW, - }, - }; - - if (pageDefinition.title) { - updateOp.$set.title = striptags(pageDefinition.title.trim()); - } - if (pageDefinition.slug) { - let pageSlug = striptags(slug(pageDefinition.slug.trim())).split('-'); - while (ObjectId.isValid(pageSlug[pageSlug.length - 1])) { - pageSlug.pop(); - } - pageSlug = pageSlug.splice(0, 4); - pageSlug.push(page._id.toString()); - updateOp.$set.slug = `${pageSlug.join('-')}`; - } - if (pageDefinition.summary) { - updateOp.$set.summary = striptags(pageDefinition.summary.trim()); - } - if (pageDefinition.content) { - updateOp.$set.content = pageDefinition.content.trim(); - } - if (pageDefinition.status) { - updateOp.$set.status = striptags(pageDefinition.status.trim()); - } - - updateOp.$set.menu = { - icon: striptags((pageDefinition.menuIcon || 'fa-slash').trim().toLowerCase()), - label: striptags((pageDefinition.menuLabel || page.title.slice(0, 10))), - order: parseInt(pageDefinition.menuOrder || '0', 10), - }; - - if (pageDefinition.parentPageId && (pageDefinition.parentPageId !== 'none')) { - updateOp.$set.menu.parent = pageDefinition.parentPageId; - } - - await Page.updateOne( - { _id: page._id }, - updateOp, - { upsert: true }, - ); - } - - async getPages (pagination, status = ['published']) { - if (!Array.isArray(status)) { - status = [status]; - } - const pages = await Page - .find({ status: { $in: status } }) - .sort({ created: -1 }) - .skip(pagination.skip) - .limit(pagination.cpp) - .lean(); - return pages; - } - - async getById (pageId) { - const page = await Page - .findById(pageId) - .select('+content') - .lean(); - return page; - } - - async getBySlug (pageSlug) { - const slugParts = pageSlug.split('-'); - const pageId = slugParts[slugParts.length - 1]; - return this.getById(pageId); - } - - async getAvailablePages (excludedPageIds) { - const search = { }; - if (excludedPageIds) { - search._id = { $nin: excludedPageIds }; - } - const pages = await Page.find(search).lean(); - return pages; - } - - async deletePage (page) { - this.log.info('deleting page', { pageId: page._id }); - await Page.deleteOne({ _id: page._id }); - } - - createPageSlug (pageId, pageTitle) { - if ((typeof pageTitle !== 'string') || (pageTitle.length < 1)) { - throw new Error('Invalid input for making a page slug'); - } - const pageSlug = slug(pageTitle.trim().toLowerCase()).split('-').slice(0, 4).join('-'); - return `${pageSlug}-${pageId}`; - } -} - -module.exports = { - slug: 'page', - name: 'page', - create: (dtp) => { return new PageService(dtp); }, -}; \ No newline at end of file diff --git a/app/services/post.js b/app/services/post.js deleted file mode 100644 index bb5edba..0000000 --- a/app/services/post.js +++ /dev/null @@ -1,183 +0,0 @@ -// post.js -// Copyright (C) 2022 DTP Technologies, LLC -// License: Apache-2.0 - -'use strict'; - -const striptags = require('striptags'); -const slug = require('slug'); - -const { SiteService } = require('../../lib/site-lib'); - -const mongoose = require('mongoose'); -const ObjectId = mongoose.Types.ObjectId; - -const Post = mongoose.model('Post'); - -class PostService extends SiteService { - - constructor (dtp) { - super(dtp, module.exports); - - this.populatePost = [ - { - path: 'author', - select: '_id username username_lc displayName bio picture', - }, - { - path: 'image', - }, - ]; - } - - async create (author, postDefinition) { - const NOW = new Date(); - - const post = new Post(); - post.created = NOW; - post.author = author._id; - post.title = striptags(postDefinition.title.trim()); - post.slug = this.createPostSlug(post._id, post.title); - post.summary = striptags(postDefinition.summary.trim()); - post.content = postDefinition.content.trim(); - post.status = postDefinition.status || 'draft'; - post.flags = { - enableComments: postDefinition.enableComments === 'on', - isFeatured: postDefinition.isFeatured === 'on', - }; - - await post.save(); - - return post.toObject(); - } - - async update (post, postDefinition) { - const NOW = new Date(); - const updateOp = { - $set: { - updated: NOW, - }, - }; - - if (postDefinition.title) { - updateOp.$set.title = striptags(postDefinition.title.trim()); - updateOp.$set.slug = this.createPostSlug(post._id, updateOp.$set.title); - } - if (postDefinition.slug) { - let postSlug = striptags(slug(postDefinition.slug.trim())).split('-'); - while (ObjectId.isValid(postSlug[postSlug.length - 1])) { - postSlug.pop(); - } - postSlug = postSlug.splice(0, 4); - postSlug.push(post._id.toString()); - updateOp.$set.slug = `${postSlug.join('-')}`; - } - if (postDefinition.summary) { - updateOp.$set.summary = striptags(postDefinition.summary.trim()); - } - if (postDefinition.content) { - updateOp.$set.content = postDefinition.content.trim(); - } - if (postDefinition.status) { - updateOp.$set.status = striptags(postDefinition.status.trim()); - } - - updateOp.$set['flags.enableComments'] = postDefinition.enableComments === 'on'; - updateOp.$set['flags.isFeatured'] = postDefinition.isFeatured === 'on'; - - await Post.updateOne( - { _id: post._id }, - updateOp, - { upsert: true }, - ); - } - - async updateImage (user, post, file) { - const { image: imageService } = this.dtp.services; - const images = [ - { - width: 960, - height: 540, - format: 'jpeg', - formatParameters: { - quality: 80, - }, - }, - ]; - await imageService.processImageFile(user, file, images); - await Post.updateOne( - { _id: post._id }, - { - $set: { - image: images[0].image._id, - }, - }, - ); - } - - async getPosts (pagination, status = ['published']) { - if (!Array.isArray(status)) { - status = [status]; - } - const posts = await Post - .find({ status: { $in: status }, 'flags.isFeatured': false }) - .sort({ created: -1 }) - .skip(pagination.skip) - .limit(pagination.cpp) - .lean(); - return posts; - } - - async getFeaturedPosts (maxCount = 3) { - const posts = await Post - .find({ status: 'published', 'flags.isFeatured': true }) - .sort({ created: -1 }) - .limit(maxCount) - .lean(); - return posts; - } - - async getAllPosts (pagination) { - const posts = await Post - .find() - .sort({ created: -1 }) - .skip(pagination.skip) - .limit(pagination.cpp) - .lean(); - return posts; - } - - async getById (postId) { - const post = await Post - .findById(postId) - .select('+content') - .populate(this.populatePost) - .lean(); - return post; - } - - async getBySlug (postSlug) { - const slugParts = postSlug.split('-'); - const postId = slugParts[slugParts.length - 1]; - return this.getById(postId); - } - - async deletePost (post) { - this.log.info('deleting post', { postId: post._id }); - await Post.deleteOne({ _id: post._id }); - } - - createPostSlug (postId, postTitle) { - if ((typeof postTitle !== 'string') || (postTitle.length < 1)) { - throw new Error('Invalid input for making a post slug'); - } - const postSlug = slug(postTitle.trim().toLowerCase()).split('-').slice(0, 4).join('-'); - return `${postSlug}-${postId}`; - } -} - -module.exports = { - slug: 'post', - name: 'post', - create: (dtp) => { return new PostService(dtp); }, -}; \ No newline at end of file diff --git a/app/views/admin/category/editor.pug b/app/views/admin/category/editor.pug deleted file mode 100644 index ad57d93..0000000 --- a/app/views/admin/category/editor.pug +++ /dev/null @@ -1,17 +0,0 @@ -extends ../layouts/main -block content - - - var formAction = category ? `/admin/category/${category._id}` : '/admin/category'; - - pre= JSON.stringify(category, null, 2) - - form(method="POST", action= formAction).uk-form - .uk-margin - label(for="name").uk-form-label Category Name - input(id="name", name="name", type="text", placeholder="Enter category name", value= category ? category.name : undefined).uk-input - - .uk-margin - label(for="description").uk-form-label Description - textarea(id="description", name="description", rows="3", placeholder="Enter category description").uk-textarea= category ? category.description : undefined - - button(type="submit").uk-button.uk-button-primary= category ? 'Update Category' : 'Create Category' \ No newline at end of file diff --git a/app/views/admin/category/index.pug b/app/views/admin/category/index.pug deleted file mode 100644 index d8e68e4..0000000 --- a/app/views/admin/category/index.pug +++ /dev/null @@ -1,21 +0,0 @@ -extends ../layouts/main -block content - - .uk-margin - div(uk-grid).uk-flex-middle - .uk-width-expand - h2 Category Manager - .uk-width-auto - a(href="/admin/category/create").uk-button.uk-button-primary - span - i.fas.fa-plus - span.uk-margin-small-left Add category - - .uk-margin - if Array.isArray(categories) && (categories.length > 0) - uk.uk-list - each category in categories - li - a(href=`/admin/category/${category._id}`)= category.name - else - h4 There are no categories. \ No newline at end of file diff --git a/app/views/admin/newsletter/editor.pug b/app/views/admin/newsletter/editor.pug deleted file mode 100644 index 6a212e6..0000000 --- a/app/views/admin/newsletter/editor.pug +++ /dev/null @@ -1,66 +0,0 @@ -extends ../layouts/main -block content - - - var actionUrl = newsletter ? `/admin/newsletter/${newsletter._id}` : `/admin/newsletter`; - - form(method="POST", action= actionUrl).uk-form - .uk-margin - label(for="title").uk-form-label.sr-only Newsletter title - input(id="title", name="title", type="text", placeholder= "Enter newsletter title", value= newsletter ? newsletter.title : undefined).uk-input - - .uk-margin - label(for="content-html").uk-form-label.sr-only Newsletter HTML body - textarea(id="content-html", name="content.html", rows="4").uk-textarea= newsletter ? newsletter.content.html : undefined - - .uk-margin - button(type="button", onclick="return dtp.app.copyHtmlToText(event, 'content-text');").uk-button.dtp-button-default Copy HTML to Text - - .uk-margin - label(for="content-text").uk-form-label.sr-only Newsletter text body - textarea(id="content-text", name="content.text", rows="4", placeholder= "Enter text-only version of newsletter.").uk-textarea= newsletter ? newsletter.content.text : undefined - - .uk-margin - label(for="summary").uk-form-label.sr-only Newsletter summary - textarea(id="summary", name="summary", rows="4", placeholder= "Enter newsletter summary (text only, no HTML)").uk-textarea= newsletter ? newsletter.summary : undefined - - button(type="submit").uk-button.dtp-button-primary= newsletter ? 'Update newsletter' : 'Save newsletter' - -block viewjs - script(src="/tinymce/tinymce.min.js") - script. - window.addEventListener('dtp-load', async ( ) => { - const toolbarItems = [ - 'undo redo', - 'formatselect', - 'bold italic backcolor', - 'alignleft aligncenter alignright alignjustify', - 'bullist numlist outdent indent removeformat', - 'link image', - 'help' - ]; - const pluginItems = [ - 'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'print', - 'preview', 'anchor', 'searchreplace', 'visualblocks', 'code', - 'fullscreen', 'insertdatetime', 'media', 'table', 'paste', 'code', - 'help', 'wordcount', - ] - - const editors = await tinymce.init({ - selector: 'textarea#content-html', - height: 500, - menubar: false, - plugins: pluginItems.join(' '), - toolbar: toolbarItems.join('|'), - branding: false, - images_upload_url: '/image/tinymce', - image_class_list: [ - { title: 'Body Image', value: 'dtp-image-body' }, - { title: 'Title Image', value: 'dtp-image-title' }, - ], - convert_urls: false, - skin: "oxide-dark", - content_css: "dark", - }); - - window.dtp.app.editor = editors[0]; - }); \ No newline at end of file diff --git a/app/views/admin/newsletter/index.pug b/app/views/admin/newsletter/index.pug deleted file mode 100644 index b0dec46..0000000 --- a/app/views/admin/newsletter/index.pug +++ /dev/null @@ -1,39 +0,0 @@ -extends ../layouts/main -block content - - .uk-margin - div(uk-grid) - .uk-width-expand - h1.uk-text-truncate Newsletters - .uk-width-auto - a(href="/admin/newsletter/compose").uk-button.dtp-button-primary - +renderButtonIcon('fa-plus', 'New Newsletter') - - .uk-margin - if (Array.isArray(newsletters) && (newsletters.length > 0)) - - ul.uk-list - - each newsletter in newsletters - - li(data-newsletter-id= newsletter._id) - div(uk-grid).uk-grid-small.uk-flex-middle - .uk-width-expand - a(href=`/admin/newsletter/${newsletter._id}`).uk-display-block.uk-text-large.uk-text-truncate= newsletter.title - - .uk-width-auto - div(uk-grid).uk-grid-small - .uk-width-auto - button( - type="button", - data-newsletter-id= newsletter._id, - data-newsletter-title= newsletter.title, - onclick="return dtp.adminApp.deleteNewsletter(event);", - ).uk-button.dtp-button-danger - +renderButtonIcon('fa-trash', 'Delete') - - .uk-width-auto - button(type="button").uk-button.dtp-button-default - +renderButtonIcon('fa-paper-plane', 'Send') - else - div There are no newsletters at this time. \ No newline at end of file diff --git a/app/views/admin/page/editor.pug b/app/views/admin/page/editor.pug deleted file mode 100644 index f1ea69a..0000000 --- a/app/views/admin/page/editor.pug +++ /dev/null @@ -1,93 +0,0 @@ -extends ../layouts/main -block content - - - var actionUrl = page ? `/admin/page/${page._id}` : `/admin/page`; - - form(method="POST", action= actionUrl).uk-form - div(uk-grid).uk-grid-small - div(class="uk-width-1-1 uk-width-2-3@m") - .uk-margin - label(for="content").uk-form-label Page body - textarea(id="content", name="content", rows="4").uk-textarea= page ? page.content : undefined - - div(class="uk-width-1-1 uk-width-1-3@m") - .uk-margin - label(for="title").uk-form-label Page title - input(id="title", name="title", type="text", placeholder= "Enter page title", value= page ? page.title : undefined).uk-input - .uk-margin - label(for="slug").uk-form-label URL slug - - - var pageSlug; - pageSlug = page ? (page.slug || 'enter-slug-here').split('-') : ['enter', 'slug', 'here', '']; - pageSlug.pop(); - pageSlug = pageSlug.join('-'); - input(id="slug", name="slug", type="text", placeholder= "Enter page URL slug", value= page ? pageSlug : undefined).uk-input - .uk-text-small The slug is used in the link to the page https://#{site.domain}/page/#{pageSlug} - div(uk-grid) - .uk-width-auto - button(type="submit").uk-button.dtp-button-primary= page ? 'Update page' : 'Create page' - .uk-margin - label(for="status").uk-form-label Status - select(id="status", name="status").uk-select - option(value="draft", selected= page ? page.status === 'draft' : true) Draft - option(value="published", selected= page ? page.status === 'published' : false) Published - option(value="archived", selected= page ? page.status === 'archived' : false) Archived - - fieldset - legend Menu - .uk-margin - label(for="menu-icon").uk-form-label Menu item icon - input(id="menu-icon", name="menuIcon", type="text", maxlength="80", placeholder="Enter icon class", value= page ? page.menu.icon : undefined).uk-input - .uk-text-small Visit #[a(href="https://fontawesome.com/v5.15/icons?d=gallery&p=2&q=blog&m=free", target="_blank") FontAwesome] for a list of usable icons. - .uk-margin - label(for="menu-label").uk-form-label Menu item label - input(id="menu-label", name="menuLabel", type="text", maxlength="80", placeholder="Enter label", value= page ? page.menu.label : undefined).uk-input - .uk-margin - label(for="menu-order").uk-form-label Menu item order - input(id="menu-order", name="menuOrder", type="number", min="0", value= page ? page.menu.order : 0).uk-input - if Array.isArray(availablePages) && (availablePages.length > 0) - .uk-margin - label(for="menu-parent").uk-form-label Parent page - select(id="menu-parent", name="parentPageId").uk-select - option(value= "none") --- Select parent page --- - each menuPage in availablePages - option(value= menuPage._id)= menuPage.title -block viewjs - script(src="/tinymce/tinymce.min.js") - script. - window.addEventListener('dtp-load', async ( ) => { - const toolbarItems = [ - 'undo redo', - 'formatselect visualblocks', - 'bold italic backcolor', - 'alignleft aligncenter alignright alignjustify', - 'bullist numlist outdent indent removeformat', - 'link image code', - 'help' - ]; - const pluginItems = [ - 'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'print', - 'preview', 'anchor', 'searchreplace', 'visualblocks', 'code', - 'fullscreen', 'insertdatetime', 'media', 'table', 'paste', 'code', - 'help', 'wordcount', - ] - - const editors = await tinymce.init({ - selector: 'textarea#content', - height: 500, - menubar: false, - plugins: pluginItems.join(' '), - toolbar: toolbarItems.join('|'), - branding: false, - images_upload_url: '/image/tinymce', - image_class_list: [ - { title: 'Body Image', value: 'dtp-image-body' }, - { title: 'Title Image', value: 'dtp-image-title' }, - ], - convert_urls: false, - skin: "oxide-dark", - content_css: "dark", - }); - - window.dtp.app.editor = editors[0]; - }); \ No newline at end of file diff --git a/app/views/admin/page/index.pug b/app/views/admin/page/index.pug deleted file mode 100644 index 84e1f50..0000000 --- a/app/views/admin/page/index.pug +++ /dev/null @@ -1,43 +0,0 @@ -extends ../layouts/main -block content - - .uk-margin - div(uk-grid) - .uk-width-expand - h1.uk-text-truncate Pages - .uk-width-auto - a(href="/admin/page/compose").uk-button.dtp-button-primary - +renderButtonIcon('fa-plus', 'New Page') - - .uk-margin - if (Array.isArray(pages) && (pages.length > 0)) - - ul.uk-list - - each page in pages - - li(data-page-id= page._id) - div(uk-grid).uk-grid-small.uk-flex-middle - .uk-width-expand - a(href=`/page/${page.slug}`).uk-display-block.uk-text-large.uk-text-truncate #{page.title} - - .uk-width-auto - div(uk-grid).uk-grid-small.uk-flex-middle - .uk-width-auto(class={ - 'uk-text-info': (page.status === 'draft'), - 'uk-text-success': (page.status === 'published'), - 'uk-text-danger': (page.status === 'archived'), - })= page.status - .uk-width-auto - a(href=`/admin/page/${page._id}`).uk-button.dtp-button-primary - +renderButtonIcon('fa-pen', 'Edit') - .uk-width-auto - button( - type="button", - data-page-id= page._id, - data-page-title= page.title, - onclick="return dtp.adminApp.deletePage(event);", - ).uk-button.dtp-button-danger - +renderButtonIcon('fa-trash', 'Delete') - else - div There are no pages at this time. \ No newline at end of file diff --git a/app/views/admin/post/editor.pug b/app/views/admin/post/editor.pug deleted file mode 100644 index 405c330..0000000 --- a/app/views/admin/post/editor.pug +++ /dev/null @@ -1,108 +0,0 @@ -extends ../layouts/main -block vendorcss - link(rel='stylesheet', href=`/cropperjs/cropper.min.css?v=${pkg.version}`) -block vendorjs - script(src=`/cropperjs/cropper.min.js?v=${pkg.version}`) -block content - - include ../../components/file-upload-image - - - var actionUrl = post ? `/admin/post/${post._id}` : `/admin/post`; - - form(method="POST", action= actionUrl).uk-form - div(uk-grid).uk-grid-small - div(class="uk-width-1-1 uk-width-2-3@m") - .uk-margin - label(for="content").uk-form-label Post body - textarea(id="content", name="content", rows="4").uk-textarea= post ? post.content : undefined - - div(class="uk-width-1-1 uk-width-1-3@m") - .uk-margin - label(for="title").uk-form-label Post title - input(id="title", name="title", type="text", placeholder= "Enter post title", value= post ? post.title : undefined).uk-input - .uk-margin - label(for="slug").uk-form-label URL slug - - - var postSlug; - if (post) { - postSlug = post.slug.split('-'); - postSlug.pop(); - postSlug = postSlug.join('-'); - } - input(id="slug", name="slug", type="text", placeholder= "Enter post URL slug", value= post ? postSlug : undefined).uk-input - .uk-text-small The slug is used in the link to the page https://#{site.domain}/post/#{post ? post.slug : 'your-slug-here'} - .uk-margin - label(for="summary").uk-form-label Post summary - textarea(id="summary", name="summary", rows="4", placeholder= "Enter post summary (text only, no HTML)").uk-textarea= post ? post.summary : undefined - div(uk-grid) - .uk-width-auto - button(type="submit").uk-button.dtp-button-primary= post ? 'Update post' : 'Create post' - .uk-margin - label(for="status").uk-form-label Status - select(id="status", name="status").uk-select - option(value="draft", selected= post ? post.status === 'draft' : true) Draft - option(value="published", selected= post ? post.status === 'published' : false) Published - option(value="archived", selected= post ? post.status === 'archived' : false) Archived - .uk-margin - div(uk-grid).uk-grid-small - .uk-width-auto - label - input(id="enable-comments", name="enableComments", type="checkbox", checked= post ? post.flags.enableComments : true).uk-checkbox - | Enable comments - .uk-width-auto - label - input(id="is-featured", name="isFeatured", type="checkbox", checked= post ? post.flags.isFeatured : false).uk-checkbox - | Featured - - if post - .uk-margin - label(for="post-image-file").uk-form-label Feature Image - +renderFileUploadImage( - `/admin/post/${post._id}/image`, - 'post-image-upload', - 'post-image-file', - 'responsive', - `/img/default-poster.jpg`, - post.image, - { aspectRatio: 16 / 9 }, - ) - -block viewjs - script(src="/tinymce/tinymce.min.js") - script. - window.addEventListener('dtp-load', async ( ) => { - const toolbarItems = [ - 'undo redo', - 'formatselect visualblocks', - 'bold italic backcolor', - 'alignleft aligncenter alignright alignjustify', - 'bullist numlist outdent indent removeformat', - 'link image code', - 'help' - ]; - const pluginItems = [ - 'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'print', - 'preview', 'anchor', 'searchreplace', 'visualblocks', 'code', - 'fullscreen', 'insertdatetime', 'media', 'table', 'paste', 'code', - 'help', 'wordcount', - ] - - const editors = await tinymce.init({ - selector: 'textarea#content', - height: 500, - menubar: false, - plugins: pluginItems.join(' '), - toolbar: toolbarItems.join('|'), - branding: false, - images_upload_url: '/image/tinymce', - image_class_list: [ - { title: 'Body Image', value: 'dtp-image-body' }, - { title: 'Title Image', value: 'dtp-image-title' }, - ], - convert_urls: false, - skin: "oxide-dark", - content_css: "dark", - }); - - window.dtp.app.editor = editors[0]; - }); \ No newline at end of file diff --git a/app/views/admin/post/index.pug b/app/views/admin/post/index.pug deleted file mode 100644 index d900b83..0000000 --- a/app/views/admin/post/index.pug +++ /dev/null @@ -1,53 +0,0 @@ -extends ../layouts/main -block content - - .uk-margin - div(uk-grid) - .uk-width-expand - h1.uk-text-truncate Posts - .uk-width-auto - a(href="/admin/post/compose").uk-button.dtp-button-primary - +renderButtonIcon('fa-plus', 'New Post') - - .uk-margin - if (Array.isArray(posts) && (posts.length > 0)) - - ul.uk-list - - each post in posts - - li(data-post-id= post._id) - div(uk-grid).uk-grid-small.uk-flex-middle - .uk-width-expand - a(href=`/post/${post.slug}`).uk-display-block.uk-text-large.uk-text-truncate #{post.title} - .uk-text-small - div(uk-grid).uk-grid-small - .uk-width-auto - span published: #{moment(post.created).format('MMM DD, YYYY [at] hh:mm:ss a')} - if post.updated - .uk-width-auto - span last update: #{moment(post.updated).format('MMM DD, YYYY [at] hh:mm:ss a')} - - .uk-width-auto - div(uk-grid).uk-grid-small.uk-flex-middle - if post.flags.isFeatured - .uk-width-auto - i(style="color: yellow;").fas.fa-star - .uk-width-auto(class={ - 'uk-text-info': (post.status === 'draft'), - 'uk-text-success': (post.status === 'published'), - 'uk-text-danger': (post.status === 'archived'), - })= post.status - .uk-width-auto - a(href=`/admin/post/${post._id}`).uk-button.dtp-button-primary - +renderButtonIcon('fa-pen', 'Edit') - .uk-width-auto - button( - type="button", - data-post-id= post._id, - data-post-title= post.title, - onclick="return dtp.adminApp.deletePost(event);", - ).uk-button.dtp-button-danger - +renderButtonIcon('fa-trash', 'Delete') - else - div There are no posts at this time. \ No newline at end of file diff --git a/app/views/category/components/list-item.pug b/app/views/category/components/list-item.pug deleted file mode 100644 index 41f5f55..0000000 --- a/app/views/category/components/list-item.pug +++ /dev/null @@ -1,6 +0,0 @@ -mixin renderCategoryListItem (category) - a(href=`/category/${category.slug}`).uk-display-block.uk-link-reset - img(src='/img/default-poster.jpg').uk-display-block.uk-margin-small.responsive.uk-border-rounded - .uk-link-reset.uk-text-bold= category.name - .uk-ling-reset.uk-text-muted #{numeral(category.stats.liveChannelCount).format("0,0")} live channels - .uk-ling-reset.uk-text-muted #{numeral(category.stats.currentViewerCount).format("0,0.0a")} viewers \ No newline at end of file diff --git a/app/views/category/home.pug b/app/views/category/home.pug deleted file mode 100644 index da7cb09..0000000 --- a/app/views/category/home.pug +++ /dev/null @@ -1,17 +0,0 @@ -extends ../layouts/main -block content - - include components/list-item - - section.uk-section.uk-section-default.uk-section-small - .uk-container.uk-container-expand - - if Array.isArray(categories) && (categories.length > 0) - div(uk-grid).uk-flex-center.uk-grid-small - each category in categories - .uk-width-auto - .uk-width-medium - .uk-margin - +renderCategoryListItem(category) - else - h4.uk-text-center There are no categories or the system is down for maintenance. \ No newline at end of file diff --git a/app/views/category/view.pug b/app/views/category/view.pug deleted file mode 100644 index 7cd7b4d..0000000 --- a/app/views/category/view.pug +++ /dev/null @@ -1,32 +0,0 @@ -extends ../layouts/main -block content - - include ../channel/components/list-item - - section(style="font: Verdana;").uk-section.uk-section-muted.uk-section-small - .uk-container - div(uk-grid).uk-grid-small - .uk-width-auto - img(src="/img/default-poster.jpg").uk-width-small - .uk-width-expand - h1.uk-margin-remove.uk-padding-remove= category.name - div= category.description - div(uk-grid).uk-grid-small - .uk-width-auto #{category.stats.streamCount} live shows. - .uk-width-auto #{category.stats.viewerCount} total viewers. - - section.uk-section.uk-section-default - .uk-container - if Array.isArray(channels) && (channels.length > 0) - div(uk-grid).uk-flex-center.uk-grid-small - each channel in channels - div(class="uk-width-1-1 uk-width-1-2@s uk-width-1-3@m uk-width-1-4@l") - +renderChannelListItem(channel) - else - .uk-text-lead No channels in this category, check back later. - include ../components/back-button - - - //- pre= JSON.stringify(category, null, 2) - pre= JSON.stringify(category, null, 2) - pre= JSON.stringify(channels, null, 2) diff --git a/app/views/components/navbar.pug b/app/views/components/navbar.pug index 21f3849..17ac0ea 100644 --- a/app/views/components/navbar.pug +++ b/app/views/components/navbar.pug @@ -14,10 +14,6 @@ nav(uk-navbar).uk-navbar-container.uk-position-fixed.uk-position-top li(class={ 'uk-active': currentView === 'home' }) a(href="/", title= "Home") +renderButtonIcon('fa-home', 'Home') - each menuItem in mainMenu - li(class={ 'uk-active': (pageSlug === menuItem.slug) }) - a(href= menuItem.url, title= menuItem.label) - +renderButtonIcon(menuItem.icon || 'fa-file', menuItem.label) div(class="uk-hidden@m").uk-navbar-center //- Site name @@ -26,10 +22,6 @@ nav(uk-navbar).uk-navbar-container.uk-position-fixed.uk-position-top a(href="/").uk-navbar-item img(src=`/img/icon/${site.domainKey}/icon-36x36.png`) - each menuItem in mainMenu - li - a(href= menuItem.url, title= menuItem.label)= menuItem.label - .uk-navbar-right if user ul.uk-navbar-nav diff --git a/app/views/components/off-canvas.pug b/app/views/components/off-canvas.pug index 0df23ee..4a535b1 100644 --- a/app/views/components/off-canvas.pug +++ b/app/views/components/off-canvas.pug @@ -20,11 +20,6 @@ mixin renderMenuItem (iconClass, label) a(href='/').uk-display-block +renderMenuItem('fa-home', 'Home') - each menuItem in mainMenu - li(class={ 'uk-active': (pageSlug === menuItem.slug) }) - a(href= menuItem.url, title= menuItem.label) - +renderMenuItem(menuItem.icon || 'fa-file', menuItem.label) - if user li.uk-nav-header Member Menu diff --git a/app/views/components/page-footer.pug b/app/views/components/page-footer.pug index 52e395f..059223b 100644 --- a/app/views/components/page-footer.pug +++ b/app/views/components/page-footer.pug @@ -1,71 +1,4 @@ -mixin renderSocialIcon (iconClass, iconLabel, url) - a(href= url).dtp-social-link - span - i(class=`fab ${iconClass}`) - span.uk-margin-small-left= iconLabel - section.uk-section.uk-section-muted.uk-section-small.dtp-site-footer .uk-container.uk-text-small.uk-text-center - ul.uk-subnav.uk-flex-center - if site.gabUrl - li - a(href= site.gabUrl).dtp-social-link - span - img(src="/img/gab-g.svg", style="width: auto; height: 1em;") - span.uk-margin-small-left Gab Social - if site.gabtvUrl - li - a(href= site.gabtvUrl).dtp-social-link - span - img(src="/img/gab-g.svg", style="width: auto; height: 1em;") - span.uk-margin-small-left Gab TV - - if site.telegramUrl - li - +renderSocialIcon('fa-telegram', 'Telegram', site.telegramUrl) - if site.twitterUrl - li - +renderSocialIcon('fa-twitter', 'Twitter', site.twitterUrl) - if site.facebookUrl - li - +renderSocialIcon('fa-facebook', 'Facebook', site.facebookUrl) - if site.instagramUrl - li - +renderSocialIcon('fa-instagram', 'Instagram', site.instagramUrl) - - if site.bitchuteUrl - li - a(href= site.bitchuteUrl).dtp-social-link - span - img(src="/img/social-icons/bitchute.svg", style="width: auto; height: 1em;") - span.uk-margin-small-left BitChute - if site.odyseeUrl - li - a(href= site.odyseeUrl).dtp-social-link - span - img(src="/img/social-icons/odysee.svg", style="width: auto; height: 1em;") - span.uk-margin-small-left Odysee - if site.rumbleUrl - li - a(href= site.odyseeUrl).dtp-social-link - span - img(src="/img/social-icons/rumble.svg", style="width: auto; height: 1em;") - span.uk-margin-small-left Rumble - if site.twitchUrl - li - +renderSocialIcon('fa-twitch', 'Twitch', site.twitchUrl) - if site.youtubeUrl - li - +renderSocialIcon('fa-youtube', 'YouTube', site.youtubeUrl) - if site.dliveUrl - li - a(href= site.dliveUrl).dtp-social-link - span - img(src="/img/social-icons/dlive.svg", style="width: auto; height: 1em;") - span.uk-margin-small-left DLive - - .uk-width-medium.uk-margin-auto - hr - - div Copyright © 2021 #[+renderSiteLink()] + div Copyright © 2021 #{site.company} div All Rights Reserved \ No newline at end of file diff --git a/app/views/components/page-sidebar.pug b/app/views/components/page-sidebar.pug index 02a97e0..54ab4fa 100644 --- a/app/views/components/page-sidebar.pug +++ b/app/views/components/page-sidebar.pug @@ -1,40 +1,9 @@ -mixin renderSidebarEpisode(episode) - .uk-card.uk-card-secondary.uk-card-small.uk-card-hover - - .uk-card-media-top - a(href= episode.url, target="_blank", title="Watch on Gab TV") - img(src=episode.image).responsive - - .uk-card-body - .uk-card-title.uk-margin-remove.uk-text-truncate - a(href= episode.url, target="_blank", title= `Watch "${episode.title}" on Gab TV`)= episode.title - .uk-text-small Posted: #{moment(episode.date_modified).format("MMM DD YYYY HH:MM a")} - mixin renderPageSidebar ( ) //- Gab TV 3 Most Recent Episodes .uk-margin - +renderSectionTitle('Gab TV', { - label: 'Visit Channel', - title: gabTvChannel.title, - url: gabTvChannel.home_page_url, + +renderSectionTitle('Widget', { + label: 'Sample URL', + title: 'Sample URL Title', + url: 'https://shing.tv', }) - - ul.uk-list - each episode in gabTvChannel.items.slice(0, 3) - li - +renderSidebarEpisode(episode) - - //- Newsletter Signup - div(uk-sticky={ offset: 60, bottom: '#dtp-content-grid' }, style="z-index: initial;") - +renderSectionTitle('Mailing List') - .uk-margin - form(method="post", action="/newsletter", onsubmit="return dtp.app.submitForm(event, 'Subscribe to newsletter');").uk-form - .uk-card.uk-card-secondary.uk-card-small - .uk-card-body - p Join the #{site.name} FREE newsletter to get show updates in your inbox. - .uk-margin - label(for="email").uk-form-label.sr-only Email Address - input(id="email", name="email", type="email", placeholder="johnsmith@example.com").uk-input - - .uk-card-footer - button(type="submit").uk-button.dtp-button-primary.uk-button-small Sign Up \ No newline at end of file + p This would be your widget content if your page even has a sidebar and that sidebar has widgets. \ No newline at end of file diff --git a/app/views/components/pwa-support.pug b/app/views/components/pwa-support.pug index 03d13b6..620d6ea 100644 --- a/app/views/components/pwa-support.pug +++ b/app/views/components/pwa-support.pug @@ -1,20 +1,20 @@ -link(rel="apple-touch-icon" sizes="57x57" href=`/img/icon/icon-57x57.png?v=${pkg.version}`) -link(rel="apple-touch-icon" sizes="60x60" href=`/img/icon/icon-60x60.png?v=${pkg.version}`) -link(rel="apple-touch-icon" sizes="72x72" href=`/img/icon/icon-72x72.png?v=${pkg.version}`) -link(rel="apple-touch-icon" sizes="76x76" href=`/img/icon/icon-76x76.png?v=${pkg.version}`) -link(rel="apple-touch-icon" sizes="114x114" href=`/img/icon/icon-114x114.png?v=${pkg.version}`) -link(rel="apple-touch-icon" sizes="120x120" href=`/img/icon/icon-120x120.png?v=${pkg.version}`) -link(rel="apple-touch-icon" sizes="144x144" href=`/img/icon/icon-144x144.png?v=${pkg.version}`) -link(rel="apple-touch-icon" sizes="152x152" href=`/img/icon/icon-152x152.png?v=${pkg.version}`) -link(rel="apple-touch-icon" sizes="180x180" href=`/img/icon/icon-180x180.png?v=${pkg.version}`) -link(rel="icon" type="image/png" sizes="32x32" href=`/img/icon/icon-32x32.png?v=${pkg.version}`) -link(rel="icon" type="image/png" sizes="96x96" href=`/img/icon/icon-96x96.png?v=${pkg.version}`) -link(rel="icon" type="image/png" sizes="16x16" href=`/img/icon/icon-16x16.png?v=${pkg.version}`) -link(rel="icon" type="image/png" sizes="512x512" href=`/img/icon/icon-512x512.png?v=${pkg.version}`) -link(rel="icon" type="image/png" sizes="384x384" href=`/img/icon/icon-384x384.png?v=${pkg.version}`) -link(rel="icon" type="image/png" sizes="256x256" href=`/img/icon/icon-512x512.png?v=${pkg.version}`) -link(rel="icon" type="image/png" sizes="192x192" href=`/img/icon/icon-192x192.png?v=${pkg.version}`) +link(rel="apple-touch-icon" sizes="57x57" href=`/img/icon/${site.domainKey}/icon-57x57.png?v=${pkg.version}`) +link(rel="apple-touch-icon" sizes="60x60" href=`/img/icon/${site.domainKey}/icon-60x60.png?v=${pkg.version}`) +link(rel="apple-touch-icon" sizes="72x72" href=`/img/icon/${site.domainKey}/icon-72x72.png?v=${pkg.version}`) +link(rel="apple-touch-icon" sizes="76x76" href=`/img/icon/${site.domainKey}/icon-76x76.png?v=${pkg.version}`) +link(rel="apple-touch-icon" sizes="114x114" href=`/img/icon/${site.domainKey}/icon-114x114.png?v=${pkg.version}`) +link(rel="apple-touch-icon" sizes="120x120" href=`/img/icon/${site.domainKey}/icon-120x120.png?v=${pkg.version}`) +link(rel="apple-touch-icon" sizes="144x144" href=`/img/icon/${site.domainKey}/icon-144x144.png?v=${pkg.version}`) +link(rel="apple-touch-icon" sizes="152x152" href=`/img/icon/${site.domainKey}/icon-152x152.png?v=${pkg.version}`) +link(rel="apple-touch-icon" sizes="180x180" href=`/img/icon/${site.domainKey}/icon-180x180.png?v=${pkg.version}`) +link(rel="icon" type="image/png" sizes="32x32" href=`/img/icon/${site.domainKey}/icon-32x32.png?v=${pkg.version}`) +link(rel="icon" type="image/png" sizes="96x96" href=`/img/icon/${site.domainKey}/icon-96x96.png?v=${pkg.version}`) +link(rel="icon" type="image/png" sizes="16x16" href=`/img/icon/${site.domainKey}/icon-16x16.png?v=${pkg.version}`) +link(rel="icon" type="image/png" sizes="512x512" href=`/img/icon/${site.domainKey}/icon-512x512.png?v=${pkg.version}`) +link(rel="icon" type="image/png" sizes="384x384" href=`/img/icon/${site.domainKey}/icon-384x384.png?v=${pkg.version}`) +link(rel="icon" type="image/png" sizes="256x256" href=`/img/icon/${site.domainKey}/icon-512x512.png?v=${pkg.version}`) +link(rel="icon" type="image/png" sizes="192x192" href=`/img/icon/${site.domainKey}/icon-192x192.png?v=${pkg.version}`) link(rel="manifest" href=`/manifest.json?v=${pkg.version}`) meta(name="msapplication-TileColor" content="#f1c52f") -meta(name="msapplication-TileImage" content=`/img/icon/ms-icon-144x144.png?v=${pkg.version}`) +meta(name="msapplication-TileImage" content=`/img/icon/${site.domainKey}/ms-icon-144x144.png?v=${pkg.version}`) meta(name="theme-color" content="#f1c52f") \ No newline at end of file diff --git a/app/views/index.pug b/app/views/index.pug index a717ce9..0e4b3a3 100644 --- a/app/views/index.pug +++ b/app/views/index.pug @@ -1,36 +1,8 @@ extends layouts/main-sidebar block content - include components/page-sidebar - include post/components/list-item - include post/components/featured-item + h1 Sample DTP Web Application + p + img(src="/img/the-bobs.jpg", alt="The Bobs have questions").uk-width-large - if site.featuredEmbed - .uk-margin!= site.featuredEmbed - - if Array.isArray(featuredPosts) && (featuredPosts.length > 0) - +renderSectionTitle('Featured Posts') - - - var topPost = featuredPosts.shift(); - .uk-margin - +renderBlogPostFeaturedItem(topPost) - - if (featuredPosts.length > 0) - .uk-margin - div(uk-grid).uk-grid-small - each post in featuredPosts - .uk-width-1-2 - +renderBlogPostFeaturedItem(post) - - //- Blog Posts - +renderSectionTitle('Blog Posts') - - if Array.isArray(posts) && (posts.length > 0) - - var postIndex = 1; - ul.uk-list.uk-list-divider.uk-list-small - each post in posts - li - +renderBlogPostListItem(post, postIndex, 4) - - postIndex += 1; - else - div There are no posts at this time. Please check back later! \ No newline at end of file + p This application doesn't actually do anything. The Bobs would have questions. \ No newline at end of file diff --git a/app/views/newsletter/index.pug b/app/views/newsletter/index.pug deleted file mode 100644 index 7e4cc10..0000000 --- a/app/views/newsletter/index.pug +++ /dev/null @@ -1,15 +0,0 @@ -extends ../layouts/main -block content - - section.uk-section.uk-section-default - .uk-container - - h1 #{site.name} Newsletters - - if Array.isArray(newsletters) && (newsletters.length > 0) - ul.uk-list - each newsletter of newsletters - li - a(href=`/newsletter/${newsletter._id}`).uk-link-reset= newsletter.title - else - div There are no newsletters at this time. Please check back later. \ No newline at end of file diff --git a/app/views/page/view.pug b/app/views/page/view.pug deleted file mode 100644 index 81b04f6..0000000 --- a/app/views/page/view.pug +++ /dev/null @@ -1,18 +0,0 @@ -extends ../layouts/main-sidebar -block content - - include ../components/page-sidebar - - article(dtp-page-id= page._id) - .uk-margin - div(uk-grid) - .uk-width-expand - h1.article-title - span - i(class=`fas ${page.menu.icon}`) - span.uk-margin-left= page.title - if user && user.flags.isAdmin - .uk-width-auto - a(href=`/admin/page/${page._id}`).uk-button.dtp-button-text EDIT - .uk-margin - != page.content diff --git a/app/views/policy/privacy.md b/app/views/policy/privacy.md index 2997192..9d185be 100644 --- a/app/views/policy/privacy.md +++ b/app/views/policy/privacy.md @@ -1,33 +1,3 @@ # Privacy Policy -## What Is Collected? - -Your email address, username, and display name are collected during account creation and retained on file with a hash of your password. The information is stored for as long as you keep your account. If you delete your account, the information is destroyed. - -IP addresses are analyzed to perform a GeoIP lookup to provide "best guess" analytics about where traffic comes from. The system does not store IP addresses, only a number of visits from Pittsburgh, PA, for example. - -## Where is information collected? - -You are asked for personal information during account signup and in your account settings. That information is your email address, username, display name, bio, and password. Your password is not stored by this system. A hash of your password is stored, instead. - -The system automates the collection of page visit statistics. We do not use a 3rd-party service to collect or analyze the data. Your IP address is not collected. Your IP address is not being stored. Aggregate stats based on a best guess of your location using GeoIP is stored. - -Information about you is collected when commenting on a post, and you are publicly attributed as the author of a comment. Your IP address is not collected or stored when commenting. Your IP address is not geolocated when commenting (only when loading the article or page). - -## Why do you collect this information? - -Your email address, username, and password are what define your user account on this website. This information is used to enable you to log in and comment on posts and other events on the site. Your email address, if you opt-in for the Newsletter, is used to deliver the Newsletter. - -Your information may be used to enter you in random drawings for giveaways and other contests. This does not happen automatically, you will be asked if you want to participate in a specific contest when they happen. If you opt-in, then you will be part of that contest. If you don't opt-in, you won't be part of the contest. - -Your information may be used to help prevent fraudulent activities and to help us prevent spam in the comments and other areas of the site. Your information is simply how you prove who you are to us. And, if we like you, we let you in. - -We do not otherwise use your information. Your information is not sold or shared with any 3rd-party entities, and will only be used by this website for the purposes stated here. - -## Your rights over your data - -You retain full rights to your data. At any time, you can close your account and all of your data will be removed (deleted). Your data is only retained by this system as long as you keep your account in good standing. - -## Who do you share information with? - -No one. At all. This website uses the information you provide to provide you with service and nothing else. \ No newline at end of file +Your site's privacy policy goes here. \ No newline at end of file diff --git a/app/views/policy/terms-of-service.md b/app/views/policy/terms-of-service.md index 7150a06..f5ecf87 100644 --- a/app/views/policy/terms-of-service.md +++ b/app/views/policy/terms-of-service.md @@ -1,305 +1,3 @@ # Terms of Service -Last Updated: December 30, 2021. - -PLEASE READ THE FOLLOWING TERMS OF SERVICE AGREEMENT CAREFULLY. BY ACCESSING OR USING OUR WEBSITE (THE "SITE") OR OUR SERVICES, YOU HEREBY AGREE TO BE BOUND BY THESE TERMS AND CONDITIONS AND ALL TERMS INCORPORATED HEREIN BY REFERENCE. IT IS THE RESPONSIBILITY OF YOU, THE USER, CUSTOMER, OR PROSPECTIVE CUSTOMER TO READ THE TERMS AND CONDITIONS BEFORE PROCEEDING TO USE THIS SITE. IF YOU DO NOT EXPRESSLY AGREE TO ALL OF THE TERMS AND CONDITIONS, THEN PLEASE DO NOT ACCESS OR USE OUR SITE OR OUR SERVICES. - -The present terms and conditions (this "Agreement" or "Terms") is a legal agreement between you and Just Joe Radio (hereinafter "JJR"), a company duly organized and validly. This Agreement annuls and voids all previous agreements. - -## OVERVIEW - -The Site (www.justjoeradio.com) is operated by JJR. Throughout the Site, the terms "we", "us" and "our" refer to JJR. JJR offers this Site, including all information, tools and services available from this Site to you, the user, conditioned upon your acceptance of all terms, conditions, policies and notices stated here. - -By visiting our Site and/or purchasing something from us, you engage in our "Service" and agree to be bound by the following terms and conditions, including those additional terms and conditions and policies referenced herein and/or available by hyperlink. These Terms apply to all users of the Site, including without limitation users who are browsers, vendors, customers, merchants, and/or contributors of content. In the event of an inconsistency between this Agreement and any additional terms or policies referenced herein, the provisions of the additional terms or policies shall control. - -Please read these Terms carefully before accessing or using our Site. By accessing or using any part of the Site, you agree to be bound by these Terms. If you do not agree to all the Terms of this Agreement, then you may not access the Site or use any Service. If these Terms are considered an offer, acceptance is expressly limited to these Terms. - -Any new features or tools which are added to the current store shall also be subject to the Terms. You can review the most current version of the Terms at any time on this page. We reserve the right to update, change or replace any part of these Terms by posting updates and/or changes to our Site. It is your responsibility to check this page periodically for changes. Your continued use of or access to the Site following the posting of any changes constitutes acceptance of those changes. - -## SECTION 1 - GENERAL TERMS - -By agreeing to these Terms, you represent that you are at least the age of majority in your state or province of residence, or that you are the age of majority in your state or province of residence and you have given us your consent to allow any of your minor dependents to use this Site. - -You may not use our products or Site for any illegal or unauthorized purpose nor may you, in the use of our products or Site, violate any laws in your jurisdiction (including but not limited to motor vehicle laws). - -You must not transmit any worms or viruses or any code of a destructive nature. - -A breach or violation of any of the Terms will result in an immediate termination of your account and right to use our Service. - -We have the right, but not the obligation, to take any of the following actions in our sole discretion at any time and for any reason without giving you any prior notice: - -1. Restrict, suspend or terminate your access to all or any part of our Site; -2. Change, suspend or discontinue all or any part of our products or Site; -3. Refuse, move, or remove any content that is available on all or any part of our Site; -4. Deactivate or delete your accounts; -5. Establish general practices and limits concerning use of our Site. - -You agree that we will not be liable to you or any third party for taking any of -these actions. - -You understand and agree that our Site may include communications such as service announcements and administrative or legal notices from us. Please note that you cannot opt out of receiving these notices. - -You understand that your content (not including credit card information), may be transferred unencrypted and involve (a) transmissions over various networks; and (b) changes to conform and adapt to technical requirements of connecting networks or devices. Credit card information is always encrypted during transfer over networks. - -You agree not to reproduce, duplicate, copy, sell, resell or exploit any portion of the Site, use of the Site, or access to the Site or any contact on the Site, without express written permission by us. - -You may not modify, publish, transmit, reverse engineer, participate in the transfer or sale, create derivative works, or in any way exploit any of the content, in whole or in part, found on the Site. JJR content is not for resale. Use of the Site does not entitle users to make any unauthorized use of any protected content, and in particular you will not delete or alter any proprietary rights or attribution notices in any content. You will use protected content solely for your personal use, and will make no other use of the content without the express written permission of JJR and the copyright owner. You agree that you do not acquire any ownership rights in any protected content. We do not grant you any licenses, express or implied, to the intellectual property of JJR or our licensors except as expressly authorizedby these Terms. - -## SECTION 2 - CREATING AN ACCOUNT - -Once you create an account with us, you are registered on the JJR Site. The terms "member," "membership," and "account" all refer to this registration as a member on JJR's Site. If you are merely surfing or browsing through the Site and have not yet created an account, your use of the Site is still subject to this Agreement; if you do not agree to this Agreement, do not use the Site. - -When you create an account, you will provide a unique username and email. We will also ask you to create a password. Because any activities that occur under your username or password are your responsibility it is important for you to keep your username and/or password secure. You may not assign or otherwise transfer your account to any other person or entity. You acknowledge that JJR is not responsible for third party access to your account that results from theft or misappropriation of your account. Notify us immediately if you believe that someone has used your username, email, or password without your authorization. - -Furthermore, the registering party hereby acknowledges, understands and agrees to: - -a) furnish factual, correct, current and complete information with regards to yourself as may be requested by the data registration process, and -b) maintain and promptly update your registration and profile information in an effort to maintain accuracy and completeness at all times. - -If anyone knowingly provides any information of a false, untrue, inaccurate or incomplete nature, Just Joe Radio will have sufficient grounds and rights to suspend or terminate the member in violation of this aspect of the Agreement, and as such refuse any and all current or future use of Just Joe Radio Services, or any portion thereof. - -## SECTION 3 - CONDUCT - -As a user or member of the Site, you herein acknowledge, understand and agree that all information, text, software, data, photographs, music, video, messages, tags or any other content, whether it is publicly or privately posted and/or transmitted, is the expressed sole responsibility of the individual from whom the content originated. In short, this means that you are solely responsible for any and all content posted, uploaded, emailed, transmitted or otherwise made available by way of the JJR Services, and as such, we do not guarantee the accuracy, integrity or quality of such content. It is expressly understood that by use of our Services, you may be exposed to content including, but not limited to, any errors or omissions in any content posted, and/or any loss or damage of any kind incurred as a result of the use of any content posted, emailed, transmitted or otherwise made available by JJR. - -Furthermore, you herein agree not to make use of Just Joe Radio's Services for the purpose of: - -a) uploading, posting, emailing, transmitting, or otherwise making available any content that shall be deemed unlawful, harmful, threatening, abusive, harassing, tortious, defamatory, libelous, or invasive of another's privacy; - -b) causing harm to minors in any manner whatsoever; - -c) impersonating any individual or entity, including, but not limited to, any JJR officials, forum leaders, guides or hosts or falsely stating or otherwise misrepresenting any affiliation with an individual or entity; - -d) forging captions, headings or titles or otherwise offering any content that you personally have no right to pursuant to any law nor having any contractual or fiduciary relationship with; - -e) uploading, posting, emailing, transmitting or otherwise offering any such content that may infringe upon any patent, copyright, trademark, or any other proprietary or intellectual rights of any other party; - -f) uploading, posting, emailing, transmitting or otherwise offering any content that you do not personally have any right to offer pursuant to any law or in accordance with any contractual or fiduciary relationship; - -g) uploading, posting, emailing, transmitting, or otherwise offering any unsolicited or unauthorized advertising, promotional flyers, "junk mail," "spam," or any other form of solicitation, except in any such areas that may have been designated for such purpose; - -h) uploading, posting, emailing, transmitting, or otherwise offering any source that may contain a software virus or other computer code, any files and/or programs which have been designed to interfere, destroy and/or limit the operation of any computer software, hardware, or telecommunication equipment; - -i) disrupting the normal flow of communication, or otherwise acting in any manner that would negatively affect other users' ability to participate in any real time interactions; - -j) interfering with or disrupting any Just Joe Radio Services, servers and/or networks that may be connected or related to our website, including, but not limited to, the use of any device software and/or routine to bypass the robot exclusion headers; - -k) intentionally or unintentionally violating any local, state, federal, national or international law, including, but not limited to, rules, guidelines, and/or regulations decreed by the U.S. Securities and Exchange Commission, in addition to any rules of any nation or other securities exchange, that would include without limitation, the New York Stock Exchange, the American Stock Exchange, or the NASDAQ, and any regulations having the force of law; - -l) providing informational support or resources, concealing and/or disguising the character, location, and or source to any organization delegated by the United States government as a "foreign terrorist organization" in accordance to Section 219 of the Immigration Nationality Act; - -m) "stalking" or with the intent to otherwise harass another individual; and/or - -n) collecting or storing of any personal data relating to any other member or user in connection with the prohibited conduct and/or activities which have been set forth in the aforementioned paragraphs. - -Just Joe Radio herein reserves the right to pre-screen, refuse and/or delete any content currently available through our Services. In addition, we reserve the right to remove and/or delete any such content that would violate the Terms or which would otherwise be considered offensive to other visitors, users and/or members. - -Just Joe Radio herein reserves the right to access, preserve and/or disclose member account information and/or content if it is requested to do so by law or in good faith belief that any such action is deemed reasonably necessary for: - -a) compliance with any legal process; - -b) enforcement of the Terms; - -c) responding to any claim that therein contained content is in violation of the rights of any third party; - -d) responding to requests for customer service; or - -e) protecting the rights, property or the personal safety of Just Joe Radio, its visitors, users and members, including the general public. - -Just Joe Radio herein reserves the right to include the use of security components that may permit digital information or material to be protected, and that such use of information and/or material is subject to usage guidelines and regulations established by Just Joe Radio or any other content providers supplying content services to Just Joe Radio. You are hereby prohibited from making any attempt to override or circumvent any of the embedded usage rules in our Services. Furthermore, unauthorized reproduction, publication, distribution, or exhibition of any information or materials supplied by our Services, despite whether done so in whole or in part, is expressly prohibited. - -## SECTION 4 - GLOBAL USE; EXPORT/IMPORT COMPLIANCE - -Due to the global nature of the internet, through the use of our network you hereby agree to comply with all local rules relating to online conduct and that which is considered acceptable content. Uploading, posting and/or transferring of software, technology and other technical data may be subject to the export and import laws of the United States and possibly other countries. Through the use of our network, you thus agree to comply with all applicable export and import laws, statutes and regulations, including, but not limited to, the Export Administration Regulations (http://www.access.gpo.gov/bis/ear/ear_data.html), as well as the -sanctions control program of the United States (http://www.treasury.gov/resource-center/sanctions/Programs/Pages/Programs.aspx). - -Furthermore, you state and pledge that you: - -a) are not on the list of prohibited individuals which may be identified on any government export exclusion report (http://www.bis.doc.gov/complianceandenforcement/liststocheck.htm) nor a member of any other government which may be part of an export-prohibited country identified in applicable export and import laws and regulations; - -b) agree not to transfer any software, technology or any other technical data through the use of our network Services to any export-prohibited country; - -c) agree not to use our website network Services for any military, nuclear, missile, chemical or biological weaponry end uses that would be a violation of the U.S. export laws; and - -d) agree not to post, transfer nor upload any software, technology or any other technical data which would be in violation of the U S. or other applicable export and/or import laws. - -## SECTION 5 - SUBMITTED CONTENT - -Just Joe Radio shall not lay claim to ownership of any content submitted by any visitor, member, or user, nor make such content available for inclusion on our website Services. Therefore, you hereby grant and allow for Just Joe Radio the below listed worldwide, royalty-free and non-exclusive licenses, as applicable: - -a) The content submitted or made available for inclusion on the publicly accessible areas of Just Joe Radio's Sites, the license provided to permit to use, distribute, reproduce, modify, adapt, publicly perform and/or publicly display said Content on our network Services is for the sole purpose of providing and promoting the specific area to which this content was placed and/or made available for viewing. This license shall be available so long as you are a member of Just Joe Radio's sites, and shall terminate at such time when you elect to discontinue your membership. - -b) Photos, audio, video and/or graphics submitted or made available for inclusion on the publicly accessible areas of Just Joe Radio's sites, the license provided to permit to use, distribute, reproduce, modify, adapt, publicly perform and/or publicly display said Content on our network Services are for the sole purpose of providing and promoting the specific area in which this content was placed and/or made available for viewing. This license shall be available so long as you are a member of Just Joe Radio's sites and shall terminate at such time when you elect to discontinue your membership. - -c) For any other content submitted or made available for inclusion on the publicly accessible areas of Just Joe Radio's sites, the continuous, binding and completely sub-licensable license which is meant to permit to use, distribute, reproduce, modify, adapt, publish, translate, publicly perform and/or publicly display said content, whether in whole or in part, and the incorporation of any such Content into other works in any arrangement or medium current used or later developed. - -Those areas which may be deemed "publicly accessible" areas of Just Joe Radio's Sites are those such areas of our network properties which are meant to be available to the general public, and which would include message boards and groups that are openly available to both users and members. However, those areas which are not open to the public, and thus available to members only, would include our mail system and instant messaging. - -### CONTRIBUTIONS TO COMPANY WEBSITE - -Just Joe Radio may provide an area for our user and members to contribute feedback to our website. When you submit ideas, documents, suggestions and/or proposals ("Contributions") to our site, you acknowledge and agree that: - -a) your contributions do not contain any type of confidential or proprietary information; - -b) JJR shall not be liable or under any obligation to ensure or maintain confidentiality, expressed or implied, related to any Contributions; - -c) JJR shall be entitled to make use of and/or disclose any such Contributions in any such manner as they may see fit; - -d) the contributor's Contributions shall automatically become the sole property of JJR; and - -e) JJR is under no obligation to either compensate or provide any form of reimbursement in any manner or nature. - -## SECTION 6 - INDEMNITY - -All users and/or members agree to insure and hold Just Joe Radio, our subsidiaries, affiliates, agents, employees, officers, partners and/or licensors blameless or not liable for any claim or demand, which may include, but is not limited to, reasonable attorney fees made by any third party which may arise from any content a member or user of our Site may submit, post, modify, transmit or otherwise make available through our Services, the use of JJR Services or your connection with these Services, your violations of the Terms of Service and/or your violation of any such rights of another person. - -## SECTION 7 - COMMERCIAL REUSE OF SERVICES - -The member or user herein agrees not to replicate, duplicate, copy, trade, sell, resell nor exploit for any commercial reason any part, use of, or access to JJR's sites. - -## SECTION 8 - MODIFICATIONS - -Just Joe Radio reserves the right at any time it may deem fit, to modify, alter and or discontinue, whether temporarily or permanently, our service, or any part thereof, with or without prior notice. In addition, we shall not be held liable to you or to any third party for any such alteration, modification, suspension and/or discontinuance of our Services, or any part thereof. - -## SECTION 9 - TERMINATION - -As a member of www.justjoeradio.com, you may cancel or terminate your account, associated email address and/or access to our Services by submitting a cancellation or termination request to . - -As a member, you agree that Just Joe Radio may, without any prior written notice, immediately suspend, terminate, discontinue and/or limit your account, any email associated with your account, and access to any of our Services. The cause for such termination, discontinuance, suspension and/or limitation of access shall include, but is not limited to: - -a) any breach or violation of our Terms or any other incorporated agreement, regulation and/or guideline; - -b) by way of requests from law enforcement or any other governmental agencies; - -c) the discontinuance, alteration and/or material modification to our Services, or any part thereof; - -d) unexpected technical or security issues and/or problems; - -e) any extended periods of inactivity; - -f) any engagement by you in any fraudulent or illegal activities; and/or - -g) the nonpayment of any associated fees that may be owed by you in connection with your www.justjoeradio.com account Services. - -Furthermore, you herein agree that any and all terminations, suspensions, discontinuances, and or limitations of access for cause shall be made at our sole discretion and that we shall not be liable to you or any other third party with regards to the termination of your account, associated email address and/or access to any of our Services. - -The termination of your account with www.justjoeradio.com shall include any and/or all of the following: - -a) the removal of any access to all or part of the Services offered within www.justjoeradio.com; - -b) the deletion of your password and any and all related information, files, and any such content that may be associated with or inside your account, or any part thereof; and - -c) the barring of any further use of all or part of our Services. - -## SECTION 10 - LINKS - -Either Just Joe Radio or any third parties may provide links to other websites and/or resources. Thus, you acknowledge and agree that we are not responsible for the availability of any such external sites or resources, and as such, we do not endorse nor are we responsible or liable for any content, products, advertising or any other materials, on or available from such third-party sites or resources. Furthermore, you acknowledge and agree that Just Joe Radio shall not be responsible or liable, directly or indirectly, for any such damage or loss which may be a result of, caused or allegedly to be caused by or in connection with the use of or the reliance on any such content, goods or Services made available on or through any such site or resource. - -## SECTION 11 - PROPRIETARY RIGHTS - -You do hereby acknowledge and agree that Just Joe Radio's Services and any essential software that may be used in connection with our Services ("Software") shall contain proprietary and confidential material that is protected by applicable intellectual property rights and other laws. Furthermore, you herein acknowledge and agree that any Content which may be contained in any advertisements or information presented by and through our Services or by advertisers is protected by copyrights, trademarks, patents or other proprietary rights and laws. Therefore, except for that which is expressly permitted by applicable law or as authorized by Just Joe Radio or such applicable licensor, you agree not to alter, modify, lease, rent, loan, sell, distribute, transmit, broadcast, publicly perform and/or created any plagiaristic works which are based on Just Joe Radio Services (e.g. Content or Software), in whole or part. - -Just Joe Radio hereby grants you a personal, non-transferable and non-exclusive right and/or license to make use of the object code or our Software on a single computer, as long as you do not, and shall not, allow any third party to duplicate, alter, modify, create or plagiarize work from, reverse engineer, reverse assemble or otherwise make an attempt to locate or discern any source code, sell, assign, sublicense, grant a security interest in and/or otherwise transfer any such right in the Software. Furthermore, you do herein agree not to alter or change the Software in any manner, nature or form, and as such, not to use any modified versions of the Software, including and without limitation, for the purpose of obtaining unauthorized access to our Services. Lastly, you also agree not to access or attempt to access our Services through any means other than through the interface which is provided by Just Joe Radio for use in accessing our Services. - -## SECTION 12 - WARRANTY DISCLAIMERS - -YOU HEREIN EXPRESSLY ACKNOWLEDGE AND AGREE THAT: - -a) THE USE OF JUST JOE RADIO SERVICES AND SOFTWARE ARE AT THE SOLE RISK BY YOU. OUR SERVICES AND SOFTWARE SHALL BE PROVIDED ON AN "AS IS" AND/OR "AS AVAILABLE" BASIS. JUST JOE RADIO AND OUR SUBSIDIARIES, AFFILIATES, OFFICERS, EMPLOYEES, AGENTS, PARTNERS AND LICENSORS EXPRESSLY DISCLAIM ANY AND ALL WARRANTIES OF ANY KIND WHETHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - -b) JUST JOE RADIO AND OUR SUBSIDIARIES, OFFICERS, EMPLOYEES, AGENTS, PARTNERS AND LICENSORS MAKE NO SUCH WARRANTIES THAT (i) JUST JOE RADIO SERVICES OR SOFTWARE WILL MEET YOUR REQUIREMENTS; (ii) JUST JOE RADIO SERVICES OR SOFTWARE SHALL BE UNINTERRUPTED, TIMELY, SECURE OR ERROR-FREE; (iii) THAT SUCH RESULTS WHICH MAY BE OBTAINED FROM THE USE OF THE JUST JOE RADIO SERVICES OR SOFTWARE WILL BE ACCURATE OR RELIABLE; (iv) QUALITY OF ANY PRODUCTS, SERVICES, ANY INFORMATION OR OTHER MATERIAL WHICH MAY BE PURCHASED OR OBTAINED BY YOU THROUGH OUR SERVICES OR SOFTWARE WILL MEET YOUR EXPECTATIONS; AND (v) THAT ANY SUCH ERRORS CONTAINED IN THE SOFTWARE SHALL BE CORRECTED. - -c) ANY INFORMATION OR MATERIAL DOWNLOADED OR OTHERWISE OBTAINED BY WAY OF JUST JOE RADIO SERVICES OR SOFTWARE SHALL BE ACCESSED BY YOUR SOLE DISCRETION AND SOLE RISK, AND AS SUCH YOU SHALL BE SOLELY RESPONSIBLE FOR AND HEREBY WAIVE ANY AND ALL CLAIMS AND CAUSES OF ACTION WITH RESPECT TO ANY DAMAGE TO YOUR COMPUTER AND/OR INTERNET ACCESS, DOWNLOADING AND/OR DISPLAYING, OR FOR ANY LOSS OF DATA THAT COULD RESULT FROM THE DOWNLOAD OF ANY SUCH INFORMATION OR MATERIAL. - -d) NO ADVICE AND/OR INFORMATION, DESPITE WHETHER WRITTEN OR ORAL, THAT MAY BE OBTAINED BY YOU FROM JUST JOE RADIO OR BY WAY OF OR FROM OUR SERVICES OR SOFTWARE SHALL CREATE ANY WARRANTY NOT EXPRESSLY STATED IN THE TERMS. - -e) A SMALL PERCENTAGE OF SOME USERS MAY EXPERIENCE SOME DEGREE OF EPILEPTIC SEIZURE WHEN EXPOSED TO CERTAIN LIGHT PATTERNS OR BACKGROUNDS THAT MAY BE CONTAINED ON A COMPUTER SCREEN OR WHILE USING OUR SERVICES. CERTAIN CONDITIONS MAY INDUCE A PREVIOUSLY UNKNOWN CONDITION OR UNDETECTED EPILEPTIC SYMPTOM IN USERS WHO HAVE SHOWN NO HISTORY OF ANY PRIOR SEIZURE OR EPILEPSY. SHOULD YOU, ANYONE YOU KNOW OR ANYONE IN YOUR FAMILY HAVE AN EPILEPTIC CONDITION, PLEASE CONSULT A PHYSICIAN IF YOU EXPERIENCE ANY OF THE FOLLOWING SYMPTOMS WHILE USING OUR SERVICES: DIZZINESS, ALTERED VISION, EYE OR MUSCLE TWITCHES, LOSS OF AWARENESS, DISORIENTATION, ANY INVOLUNTARY MOVEMENT, OR CONVULSIONS. - -## SECTION 13 - LIMITATION OF LIABILITY - -YOU EXPLICITLY ACKNOWLEDGE, UNDERSTAND AND AGREE THAT JUST JOE RADIO AND OUR SUBSIDIARIES, AFFILIATES, OFFICERS, EMPLOYEES, AGENTS, PARTNERS AND LICENSORS SHALL NOT BE LIABLE TO YOU FOR ANY PUNITIVE, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DAMAGES WHICH MAY BE RELATED TO THE LOSS OF ANY PROFITS, GOODWILL, USE, DATA AND/OR OTHER INTANGIBLE LOSSES, EVEN THOUGH WE MAY HAVE BEEN ADVISED OF SUCH POSSIBILITY THAT SAID DAMAGES MAY OCCUR, AND RESULT FROM: - -a) THE USE OR INABILITY TO USE OUR SERVICE; - -b) THE COST OF PROCURING SUBSTITUTE GOODS AND SERVICES; - -c) UNAUTHORIZED ACCESS TO OR THE ALTERATION OF YOUR TRANSMISSIONS AND/OR DATA; - -d) STATEMENTS OR CONDUCT OF ANY SUCH THIRD PARTY ON OUR SERVICE; - -e) AND ANY OTHER MATTER WHICH MAY BE RELATED TO OUR SERVICE. - -## SECTION 14 - RELEASE - -In the event you have a dispute, you agree to release Just Joe Radio (and its officers, directors, employees, agents, parent subsidiaries, affiliates, co-branders, partners and any other third parties) from claims, demands and damages (actual and consequential) of every kind and nature, known and unknown, suspected or unsuspected, disclosed and undisclosed, arising out of or in any way connected to such dispute. - -## SECTION 15 - NOTICE - -Just Joe Radio may furnish you with notices, including those with regards to any changes to the Terms, including but not limited to email, regular mail, MMS or SMS, text messaging, postings on our website Services, or other reasonable means currently known or any which may be herein after developed. Any such notices may not be received if you violate any aspects of the Terms by accessing our Services in an unauthorized manner. Your acceptance of this Agreement constitutes your agreement that you are deemed to have received any and all notices that would have been delivered had you accessed our Services in an authorized manner. - -## SECTION 16 - INTELLECTUAL PROPERTY RIGHTS - -You herein acknowledge, understand and agree that all of the Just Joe Radio trademarks, copyright, trade name, service marks, and other Just Joe Radio logos and any brand features, and/or product and service names are trademarks and as such, are and shall remain the property of Just Joe Radio. You herein agree not to display and/or use in any manner the Just Joe Radio logo or marks without obtaining Just Joe Radio's prior written consent. - -Just Joe Radio will always respect the intellectual property of others, and we ask that all of our users do the same. With regards to appropriate circumstances and at its sole discretion, Just Joe Radio may disable and/or terminate the accounts of any user who violates our Terms and/or infringes the rights of others. If you feel that your work has been duplicated in such a way that would constitute copyright infringement, or if you believe your intellectual property rights have been otherwise violated, you should provide to us the following information: - -a) The electronic or the physical signature of the individual that is authorized on behalf of the owner of the copyright or other intellectual property interest; - -b) A description of the copyrighted work or other intellectual property that you believe has been infringed upon; - -c) A description of the location of the site which you allege has been infringing upon your work; - -d) Your physical address, telephone number, and email address; - -e) A statement, in which you state that the alleged and disputed use of your work is not authorized by the copyright owner, its agents or the law; - -f) And finally, a statement, made under penalty of perjury, that the aforementioned information in your notice is truthful and accurate, and that you are the copyright or intellectual property owner, representative or agent authorized to act on the copyright or intellectual property owner's behalf. - -The Just Joe Radio agent for notice of claims of copyright or other intellectual property infringement can be contacted as follows: - -Email: joe@justjoeradio.com - -## SECTION 17 - ENTIRE AGREEMENT - -This Agreement constitutes the entire agreement between you and Just Joe Radio and shall govern the use of our Services, superseding any prior version of this Agreement between you and us with respect to Just Joe Radio Services. You may also be subject to additional terms and conditions that may apply when you use or purchase certain other Just Joe Radio Services, affiliate Services, third-party content or third-party software. - -## SECTION 18 - CHOICE OF LAW AND FORUM - -It is at the mutual agreement of both you and Just Joe Radio with regard to the Agreement that the relationship between the parties shall be governed by the laws of the state of Texas without regard to its conflict of law provisions and that any and all claims, causes of action and/or disputes, arising out of or relating to the Agreement, or the relationship between you and Just Joe Radio, shall be filed within the courts having jurisdiction within the County of , or the U.S. District Court located in said state. You and Just Joe Radio agree to submit to the jurisdiction of the courts as previously mentioned, and agree to waive any and all objections to the exercise of jurisdiction over the parties by such courts and to venue in such courts. - -## SECTION 19 - WAIVER AND SEVERABILITY OF TERMS - -At any time, should Just Joe Radio fail to exercise or enforce any right or provision of the Agreement, such failure shall not constitute a waiver of such right or provision. If any provision of this Agreement is found by a court of competent jurisdiction to be invalid, the parties nevertheless agree that the court should endeavor to give effect to the parties' intentions as reflected in the provision, and the other provisions of the Agreement remain in full force and effect. - -## SECTION 20 - NO RIGHT OF SURVIVORSHIP NON-TRANSFERABILITY - -You acknowledge, understand and agree that your account is non-transferable and any rights to your ID and/or contents within your account shall terminate upon your death. Upon receipt of a copy of a death certificate, your account may be terminated and all contents therein permanently deleted. - -## SECTION 21 - STATUTE OF LIMITATIONS - -You acknowledge, understand and agree that regardless of any statute or law to the contrary, any claim or action arising out of or related to the use of our Services or the Agreement must be filed within year(s) after said claim or cause of action arose or shall be forever barred. - -## SECTION 22 - VIOLATIONS - -Please report any and all violations of this Agreement to Just Joe Radio as follows: - -Email: -joe@justjoeradio.com - -## SECTION 23 - GOVERNMENT REQUESTS - -In order to cooperate with governmental requests, subpoenas or court orders, to protect our systems, or to ensure the integrity and operation of our business and systems, we may access and disclose any information we consider necessary or appropriate, including and without limitation, your information, IP address, and usage history. Our right to disclose any such information is governed by the terms of our Privacy Policy. - -## SECTION 24 - FOREIGN ACCESS OF SITE - -The Site is controlled, operated and administered by JJR from our offices within the USA. If you access the Site from a location outside the USA, you are responsible for compliance with all local laws. You agree that you will not use JJR's content accessed through the Site in any country or in any manner prohibited by any applicable laws, restrictions or regulations. - -## SECTION 25 - ERRORS, INACCURACIES AND OMISSIONS - -Occasionally there may be information on our Site that contains typographical errors, inaccuracies or omissions that may relate to product descriptions, pricing, promotions, offers, product shipping charges, transit times and availability. We reserve the right to correct any errors, inaccuracies or omissions, and to change or update information or cancel orders if any information on the Site or on any related Site is inaccurate at any time without prior notice (including after you have submitted your order). - -We undertake no obligation to update, amend or clarify information on the Site or on any related Site, including without limitation, pricing information, except as required by law. No specified update or refresh date applied on the Site or on any related Site, should be taken to indicate that all information on the Site or on any related Site has been modified or updated. - -## SECTION 26 - PRIVACY POLICY - -Every member's registration data and various other personal information are strictly protected by the Just Joe Radio Online Privacy Policy (see the full Privacy Policy at [https://justjoeradio.com/policy/privacy](https://justjoeradio.com/policy/privacy)). As a member, you herein consent to the collection and use of the information provided, including the transfer of information within the United States and/or other countries for storage, processing or use by Just Joe Radio and/or our subsidiaries and affiliates. \ No newline at end of file +Your site's Terms of Service go here. \ No newline at end of file diff --git a/app/views/post/components/featured-item.pug b/app/views/post/components/featured-item.pug deleted file mode 100644 index 73db7e2..0000000 --- a/app/views/post/components/featured-item.pug +++ /dev/null @@ -1,15 +0,0 @@ -mixin renderBlogPostFeaturedItem (post) - a(href=`/post/${post.slug}`).uk-display-block.uk-link-reset - div(class='uk-visible@m').uk-margin-small - if post.image - img(src= `/image/${post.image._id}`).responsive - else - img(src="/img/default-poster.jpg").responsive - - article.uk-article - h4(style="line-height: 1.1;").uk-article-title.uk-margin-small= post.title - .uk-article-meta - if post.updated - span updated: #{moment(post.updated).format("MMM DD YYYY HH:MM a")} - else - span published: #{moment(post.created).format("MMM DD YYYY HH:MM a")} \ No newline at end of file diff --git a/app/views/post/components/list-item.pug b/app/views/post/components/list-item.pug deleted file mode 100644 index 02bbce8..0000000 --- a/app/views/post/components/list-item.pug +++ /dev/null @@ -1,24 +0,0 @@ -mixin renderBlogPostListItem (post, postIndex = 1, postIndexModulus = 3) - a(href=`/post/${post.slug}`).uk-display-block.uk-link-reset - div(uk-grid).uk-grid-small - - div(class='uk-visible@m', class={ - 'uk-flex-first': ((postIndex % postIndexModulus) === 0), - 'uk-flex-last': ((postIndex % postIndexModulus) !== 0), - }).uk-width-1-3 - if post.image - img(src= `/image/${post.image._id}`).responsive - else - img(src="/img/default-poster.jpg").responsive - - div(class='uk-width-1-1 uk-width-2-3@m', class={ - 'uk-flex-first': ((postIndex % postIndexModulus) !== 0), - 'uk-flex-last': ((postIndex % postIndexModulus) === 0), - }) - article.uk-article - h4(style="line-height: 1.1;").uk-article-title.uk-margin-small= post.title - .uk-article-meta - if post.updated - span updated: #{moment(post.updated).format("MMM DD YYYY HH:MM a")} - else - span published: #{moment(post.created).format("MMM DD YYYY HH:MM a")} \ No newline at end of file diff --git a/app/views/post/view.pug b/app/views/post/view.pug deleted file mode 100644 index 337995d..0000000 --- a/app/views/post/view.pug +++ /dev/null @@ -1,66 +0,0 @@ -extends ../layouts/main-sidebar -block content - - include ../comment/components/comment-list - include ../comment/components/composer - - article(dtp-post-id= post._id) - .uk-margin - h1.article-title= post.title - .uk-text-lead= post.summary - .uk-margin - .uk-article-meta - div(uk-grid).uk-grid-small.uk-flex-top - .uk-width-expand - div #{moment(post.created).format('MMM DD, YYYY, hh:mm a')}, by #[a(href=`/user/${post.author._id}`)= post.author.displayName || post.author.username] - if user && user.flags.isAdmin - .uk-width-auto - a(href=`/admin/post/${post._id}`) - +renderButtonIcon('fa-pen', 'edit') - .uk-width-auto - +renderButtonIcon('fa-eye', displayIntegerValue(post.stats.totalViewCount)) - .uk-width-auto - +renderButtonIcon('fa-chevron-up', displayIntegerValue(post.stats.upvoteCount)) - .uk-width-auto - +renderButtonIcon('fa-chevron-down', displayIntegerValue(post.stats.downvoteCount)) - .uk-width-auto - +renderButtonIcon('fa-comment', displayIntegerValue(post.stats.commentCount)) - .uk-margin - != post.content - - if post.updated - .uk-margin - .uk-article-meta This post was updated on #{moment(post.updated).format('MMMM DD, YYYY, [at] hh:mm a')}. - - .uk-margin - h4 Post author - div(uk-grid).uk-grid-small - if post.author.picture && post.author.picture.small - .uk-width-auto - img(src=`/image/${post.author.picture.small}`) - .uk-width-expand - .uk-text-bold= post.author.displayName || post.author.username - .uk-text-small= post.author.bio - - if user && post.flags.enableComments && user.permissions.canComment - +renderSectionTitle('Add a comment') - - .uk-margin - +renderCommentComposer(`/post/${post._id}/comment`) - - if featuredComment - #featured-comment.uk-margin-large - .uk-margin - +renderSectionTitle('Linked Comment') - +renderComment(featuredComment) - - .uk-margin - +renderSectionTitle('Comments') - - .uk-margin - if Array.isArray(comments) && (comments.length > 0) - ul#post-comment-list.uk-list.uk-list-divider.uk-list-large - +renderCommentList(comments, { countPerPage, rootUrl: `/post/${post.slug}/comment` }) - else - ul#post-comment-list.uk-list.uk-list-divider.uk-list-large - div There are no comments at this time. Please check back later. \ No newline at end of file diff --git a/client/img/the-bobs.jpg b/client/img/the-bobs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..832826222fa07e984b6241013e966ed6dd02ce6e GIT binary patch literal 115202 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

@<36M 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 XYVV>Nt^Iz`{YUnkk9dU?rVszw04=*x literal 0 HcmV?d00001 diff --git a/lib/site-platform.js b/lib/site-platform.js index 569814d..783efdb 100644 --- a/lib/site-platform.js +++ b/lib/site-platform.js @@ -200,8 +200,6 @@ module.exports.startPlatform = async (dtp) => { }; module.exports.startWebServer = async (dtp) => { - const { page: pageService } = module.services; - dtp.app = module.app = express(); module.app.set('views', path.join(dtp.config.root, 'app', 'views')); @@ -339,7 +337,6 @@ module.exports.startWebServer = async (dtp) => { return next(error); } }); - module.app.use(pageService.menuMiddleware.bind(pageService)); /* * System Init