From cc7e5ad02f7ae33bba8b810dfc2b246fb2992c81 Mon Sep 17 00:00:00 2001 From: Andrew Woodlee Date: Sat, 5 Nov 2022 08:49:14 -0500 Subject: [PATCH 1/5] changed _id to username for profile access --- app/controllers/user.js | 6 +++--- app/views/components/library.pug | 8 ++++---- app/views/components/navbar.pug | 2 +- app/views/components/off-canvas.pug | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/controllers/user.js b/app/controllers/user.js index c5cda71..5edf028 100644 --- a/app/controllers/user.js +++ b/app/controllers/user.js @@ -33,12 +33,12 @@ class UserController extends SiteController { const otpSetup = otpAuthService.middleware('Account', { adminRequired: false, otpRequired: true, - otpRedirectURL: async (req) => { return `/user/${req.user._id}`; }, + otpRedirectURL: async (req) => { return `/user/${req.user.username}`; }, }); const otpMiddleware = otpAuthService.middleware('Account', { adminRequired: false, otpRequired: false, - otpRedirectURL: async (req) => { return `/user/${req.user._id}`; }, + otpRedirectURL: async (req) => { return `/user/${req.user.username}`; }, }); router.use( @@ -203,7 +203,7 @@ class UserController extends SiteController { if (error) { return next(error); } - res.redirect(`/user/${res.locals.user._id}`); + res.redirect(`/user/${res.locals.user.username}`); }); } catch (error) { this.log.error('failed to create new user', { error }); diff --git a/app/views/components/library.pug b/app/views/components/library.pug index b9ef8b9..9424f97 100644 --- a/app/views/components/library.pug +++ b/app/views/components/library.pug @@ -40,9 +40,9 @@ include section-title function getUserProfileUrl (user) { if (user.core) { - return `/user/core/${user._id}`; + return `/user/core/${user.username}`; } - return `/user/${user._id}`; + return `/user/${user.username}`; } mixin renderCell (label, value, className) @@ -60,6 +60,6 @@ mixin renderBackButton (options) mixin renderUserLink (user) if user.coreUserId - a(href=`/user/core/${user._id}`)= `${user.username}@${user.core.meta.domainKey}` + a(href=`/user/core/${user.username}`)= `${user.username}@${user.core.meta.domainKey}` else - a(href=`/user/${user._id}`)= user.displayName || user.username \ No newline at end of file + a(href=`/user/${user.username}`)= user.displayName || user.username \ No newline at end of file diff --git a/app/views/components/navbar.pug b/app/views/components/navbar.pug index 9b86622..3b0025b 100644 --- a/app/views/components/navbar.pug +++ b/app/views/components/navbar.pug @@ -47,7 +47,7 @@ nav(uk-navbar).uk-navbar-container.uk-position-fixed.uk-position-top li.uk-nav-heading.uk-text-center= user.displayName || user.username li.uk-nav-divider li - a(href= user.core ? `/user/core/${user._id}` : `/user/${user._id}`) + a(href= user.core ? `/user/core/${user.username}` : `/user/${user.username}`) span.nav-item-icon i.fas.fa-user span Profile diff --git a/app/views/components/off-canvas.pug b/app/views/components/off-canvas.pug index acd1a62..f20c996 100644 --- a/app/views/components/off-canvas.pug +++ b/app/views/components/off-canvas.pug @@ -40,7 +40,7 @@ mixin renderMenuItem (iconClass, label) .uk-width-expand Chat li(class={ "uk-active": (currentView === 'user-settings') }) - a(href=`/user/${user._id}`).uk-display-block + a(href=`/user/${user.username}`).uk-display-block div(uk-grid).uk-grid-collapse .uk-width-auto .app-menu-icon From e83e37394d3870727bd59cf3ec6d55af8b986dbf Mon Sep 17 00:00:00 2001 From: rob Date: Sun, 6 Nov 2022 16:26:20 -0500 Subject: [PATCH 2/5] more progress towards /user/:username --- app/controllers/user.js | 25 ++++++++++++++++----- app/services/user.js | 50 ++++++++++++++++++++++------------------- 2 files changed, 47 insertions(+), 28 deletions(-) diff --git a/app/controllers/user.js b/app/controllers/user.js index 5edf028..dbdbeaa 100644 --- a/app/controllers/user.js +++ b/app/controllers/user.js @@ -60,8 +60,9 @@ class UserController extends SiteController { return next(); } - router.param('userId', this.populateUser.bind(this)); - router.param('coreUserId', this.populateCoreUser.bind(this)); + router.param('username', this.populateUsername.bind(this)); + router.param('userId', this.populateUserId.bind(this)); + router.param('coreUserId', this.populateCoreUserId.bind(this)); router.post( '/core/:coreUserId/settings', @@ -131,7 +132,7 @@ class UserController extends SiteController { this.getUserSettingsView.bind(this), ); router.get( - '/:userId', + '/:username', limiterService.createMiddleware(limiterService.config.user.getUserProfile), authRequired, otpMiddleware, @@ -147,7 +148,21 @@ class UserController extends SiteController { ); } - async populateUser (req, res, next, userId) { + async populateUsername (req, res, next, username) { + const { user: userService } = this.dtp.services; + try { + res.locals.userProfile = await userService.getPublicProfile('User', username); + if (!res.locals.userProfile) { + throw new SiteError(404, 'Member not found'); + } + return next(); + } catch (error) { + this.log.error('failed to populate username with public profile', { username, error }); + return next(error); + } + } + + async populateUserId (req, res, next, userId) { const { user: userService } = this.dtp.services; try { userId = mongoose.Types.ObjectId(userId); @@ -163,7 +178,7 @@ class UserController extends SiteController { } } - async populateCoreUser (req, res, next, coreUserId) { + async populateCoreUserId (req, res, next, coreUserId) { const { coreNode: coreNodeService } = this.dtp.services; try { coreUserId = mongoose.Types.ObjectId(coreUserId); diff --git a/app/services/user.js b/app/services/user.js index 76d28a7..d3f83ea 100644 --- a/app/services/user.js +++ b/app/services/user.js @@ -459,7 +459,7 @@ class UserService extends SiteService { return user; } - async getPublicProfile (username) { + async getPublicProfile (type, username) { if (!username || (typeof username !== 'string')) { throw new SiteError(406, 'Invalid username'); } @@ -469,28 +469,32 @@ class UserService extends SiteService { throw new SiteError(406, 'Invalid username'); } - /** - * Try to resolve the user as a CoreUser - */ - let user = await CoreUser - .findOne({ username_lc: username }) - .select('_id created username username_lc displayName bio picture header core') - .populate(this.populateUser) - .lean(); - if (user) { - user.type = 'CoreUser'; - } else { - /* - * Try to resolve the user as a local User - */ - user = await User - .findOne({ username_lc: username }) - .select('_id created username username_lc displayName bio picture header') - .populate(this.populateUser) - .lean(); - if (user) { - user.type = 'User'; - } + let user; + switch (type) { + case 'CoreUser': + user = await CoreUser + .findOne({ username_lc: username }) + .select('_id created username username_lc displayName bio picture header core') + .populate(this.populateUser) + .lean(); + if (user) { + user.type = 'CoreUser'; + } + break; + + case 'User': + user = await User + .findOne({ username_lc: username }) + .select('_id created username username_lc displayName bio picture header') + .populate(this.populateUser) + .lean(); + if (user) { + user.type = 'User'; + } + break; + + default: + throw new SiteError(400, 'Invalid user account type'); } return user; From eda1d020c206370b1cf1cdfaeecade87e3247af0 Mon Sep 17 00:00:00 2001 From: rob Date: Sun, 6 Nov 2022 17:06:46 -0500 Subject: [PATCH 3/5] made newsfeed a top-level middleware integration --- app/controllers/home.js | 8 +------- app/services/feed.js | 11 +++++++++++ dtp-webapp.js | 6 +++++- lib/site-common.js | 7 +++++++ 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/app/controllers/home.js b/app/controllers/home.js index 292704b..6c459cb 100644 --- a/app/controllers/home.js +++ b/app/controllers/home.js @@ -63,19 +63,13 @@ class HomeController extends SiteController { } async getHome (req, res, next) { - const { - announcement: announcementService, - feed: feedService, - hive: hiveService, - } = this.dtp.services; + const { announcement: announcementService, hive: hiveService } = this.dtp.services; try { res.locals.announcements = await announcementService.getLatest(req.user); res.locals.pagination = this.getPaginationParameters(req, 20); res.locals.constellationTimeline = await hiveService.getConstellationTimeline(req.user, res.locals.pagination); - res.locals.newsfeed = await feedService.getNewsfeed(); - res.render('index'); } catch (error) { this.log.error('failed to render home view', { error }); diff --git a/app/services/feed.js b/app/services/feed.js index baefc5d..ea9a684 100644 --- a/app/services/feed.js +++ b/app/services/feed.js @@ -27,6 +27,17 @@ class FeedService extends SiteService { this.jobQueue = await this.getJobQueue('newsroom', this.dtp.config.jobQueues.newsroom); } + middleware (options) { + options = Object.assign({ maxEntryCount: 5 }, options); + return async (req, res, next) => { + if (this.isSystemRoute(req.path)) { + return next(); // don't load newsfeeds for non-content routes + } + res.locals.newsfeed = await this.getNewsfeed({ skip: 0, cpp: options.maxEntryCount }); + return next(); + }; + } + async create (feedDefinition) { feedDefinition.url = feedDefinition.url.trim(); const feedContent = await this.load(feedDefinition.url); diff --git a/dtp-webapp.js b/dtp-webapp.js index 23e3354..1dd4cc1 100644 --- a/dtp-webapp.js +++ b/dtp-webapp.js @@ -21,12 +21,16 @@ module.config = { site: require(path.join(module.rootPath, 'config', 'site')), http: require(path.join(module.rootPath, 'config', 'http')), https: require(path.join(module.rootPath, 'config', 'https')), + registerMiddleware: async (dtp, app) => { + const { feed: feedService } = dtp.services; + app.use(feedService.middleware({ maxEntryCount: 5 })); + }, }; module.log = new SiteLog(module, module.config.component); module.shutdown = async ( ) => { - + await SitePlatform.shutdown(); }; (async ( ) => { diff --git a/lib/site-common.js b/lib/site-common.js index 78a1788..3732ce3 100644 --- a/lib/site-common.js +++ b/lib/site-common.js @@ -106,6 +106,13 @@ class SiteCommon extends EventEmitter2 { }); } + isSystemRoute (pathname) { + return pathname.startsWith('/auth') || + pathname.startsWith('/image') || + pathname.startsWith('/manifest') + ; + } + isValidString (text) { return text && (typeof text === 'string') && (text.length > 0); } From ac0bea89c158d389a06bba8cb500f41d1eb6711a Mon Sep 17 00:00:00 2001 From: rob Date: Sun, 6 Nov 2022 17:06:53 -0500 Subject: [PATCH 4/5] small ui enhancements --- app/views/admin/layouts/main.pug | 7 +------ app/views/layouts/main-sidebar.pug | 2 ++ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/app/views/admin/layouts/main.pug b/app/views/admin/layouts/main.pug index 1bfa06e..1246214 100644 --- a/app/views/admin/layouts/main.pug +++ b/app/views/admin/layouts/main.pug @@ -4,11 +4,6 @@ block vendorcss block content-container - block page-header - section.uk-section.uk-section-header.uk-section-xsmall - .uk-container - h1.uk-text-center.uk-margin-remove #{site.name} Admin - block admin-layout section.uk-section.uk-section-default.uk-section-small @@ -21,4 +16,4 @@ block content-container include ../components/menu div(class="uk-width-1-1 uk-flex-first uk-width-expand@m").uk-width-expand - block content + block content \ No newline at end of file diff --git a/app/views/layouts/main-sidebar.pug b/app/views/layouts/main-sidebar.pug index 52cbef8..2a67a50 100644 --- a/app/views/layouts/main-sidebar.pug +++ b/app/views/layouts/main-sidebar.pug @@ -1,6 +1,8 @@ extends main block content-container + block content-header + section.uk-section.uk-section-default.uk-section-small .uk-container div(uk-grid)#dtp-content-grid From 375d08226cb325e9196c6026ce7010451a1ccd70 Mon Sep 17 00:00:00 2001 From: rob Date: Sun, 6 Nov 2022 23:01:14 -0500 Subject: [PATCH 5/5] newsroom feed entry list item and link presentation touch-ups --- app/views/newsroom/components/feed-entry-list-item.pug | 10 +++++----- client/less/site/main.less | 7 +++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/views/newsroom/components/feed-entry-list-item.pug b/app/views/newsroom/components/feed-entry-list-item.pug index da32d31..d50b368 100644 --- a/app/views/newsroom/components/feed-entry-list-item.pug +++ b/app/views/newsroom/components/feed-entry-list-item.pug @@ -1,9 +1,9 @@ mixin renderNewsroomFeedEntryListItem (entry) - .uk-text-bold - a(href= entry.link, target="_blank").uk-link-reset= entry.title - .uk-text-small - div(uk-grid).uk-grid-small - .uk-width-expand + a(href= entry.link, target="_blank").dtp-link + div= entry.title + .uk-article-meta + div(uk-grid).uk-grid-small.uk-grid-divider + .uk-width-auto.uk-text-truncate a(href= entry.feed.link, target="_blank").uk-link-reset= entry.feed.title .uk-width-auto div= moment(entry.published).fromNow() \ No newline at end of file diff --git a/client/less/site/main.less b/client/less/site/main.less index 26e3198..f630285 100644 --- a/client/less/site/main.less +++ b/client/less/site/main.less @@ -50,6 +50,13 @@ body { } } +a.dtp-link { + color: inherit; + + &:hover { + color: @global-link-hover-color; + } +} .dtp-site-footer { .uk-subnav { a.dtp-social-link {