@ -1,91 +0,0 @@ |
|||
// admin/domain.js
|
|||
// Copyright (C) 2021 Digital Telepresence, LLC
|
|||
// License: Apache-2.0
|
|||
|
|||
'use strict'; |
|||
|
|||
const express = require('express'); |
|||
|
|||
const { /*SiteError,*/ SiteController } = require('../../../lib/site-lib'); |
|||
|
|||
class DomainController extends SiteController { |
|||
|
|||
constructor (dtp) { |
|||
super(dtp, 'admin:domain'); |
|||
} |
|||
|
|||
async start ( ) { |
|||
const router = express.Router(); |
|||
router.use(async (req, res, next) => { |
|||
res.locals.currentView = 'admin'; |
|||
res.locals.adminView = 'domain'; |
|||
return next(); |
|||
}); |
|||
|
|||
router.param('domainId', this.populateDomainId.bind(this)); |
|||
|
|||
router.post('/:domainId', this.postUpdateDomain.bind(this)); |
|||
router.post('/', this.postCreateDomain.bind(this)); |
|||
|
|||
router.get('/create', this.getCreateForm.bind(this)); |
|||
router.get('/:domainId', this.getDomainView.bind(this)); |
|||
|
|||
router.get('/', this.getHomeView.bind(this)); |
|||
|
|||
return router; |
|||
} |
|||
|
|||
async populateDomainId (req, res, next, domainId) { |
|||
const { domain: domainService } = this.dtp.services; |
|||
try { |
|||
res.locals.domain = await domainService.getById(domainId); |
|||
return next(); |
|||
} catch (error) { |
|||
return next(error); |
|||
} |
|||
} |
|||
|
|||
async postUpdateDomain (req, res, next) { |
|||
const { domain: domainService } = this.dtp.services; |
|||
try { |
|||
await domainService.update(res.locals.domain, req.body); |
|||
res.redirect('/admin/domain'); |
|||
} catch (error) { |
|||
return next(error); |
|||
} |
|||
} |
|||
|
|||
async postCreateDomain (req, res, next) { |
|||
const { domain: domainService } = this.dtp.services; |
|||
try { |
|||
res.locals.domain = await domainService.create(req.body); |
|||
res.redirect(`/admin/domain/${res.locals.domain._id}`); |
|||
} catch (error) { |
|||
return next(error); |
|||
} |
|||
} |
|||
|
|||
async getDomainView (req, res) { |
|||
res.render('admin/domain/form'); |
|||
} |
|||
|
|||
async getCreateForm (req, res) { |
|||
res.render('admin/domain/form'); |
|||
} |
|||
|
|||
async getHomeView (req, res, next) { |
|||
const { domain: domainService } = this.dtp.services; |
|||
try { |
|||
res.locals.pagination = this.getPaginationParameters(req, 10); |
|||
res.locals.domains = await domainService.getDomains(res.locals.pagination); |
|||
res.render('admin/domain/index'); |
|||
} catch (error) { |
|||
return next(error); |
|||
} |
|||
} |
|||
} |
|||
|
|||
module.exports = async (dtp) => { |
|||
let controller = new DomainController(dtp); |
|||
return controller; |
|||
}; |
@ -1,21 +0,0 @@ |
|||
// domain.js
|
|||
// Copyright (C) 2021 Digital Telepresence, LLC
|
|||
// License: Apache-2.0
|
|||
|
|||
'use strict'; |
|||
|
|||
const mongoose = require('mongoose'); |
|||
|
|||
const Schema = mongoose.Schema; |
|||
|
|||
const DomainSchema = new Schema({ |
|||
created: { type: Date, default: Date.now, required: true, index: -1 }, |
|||
name: { type: String, required: true, lowercase: true, index: 1 }, |
|||
stats: { |
|||
channelCount: { type: Number, default: 0, required: true }, |
|||
streamCount: { type: Number, default: 0, required: true }, |
|||
viewerCount: { type: Number, default: 0, required: true }, |
|||
}, |
|||
}); |
|||
|
|||
module.exports = mongoose.model('Domain', DomainSchema); |
@ -1,72 +0,0 @@ |
|||
// domain.js
|
|||
// Copyright (C) 2021 Digital Telepresence, LLC
|
|||
// License: Apache-2.0
|
|||
|
|||
'use strict'; |
|||
|
|||
const striptags = require('striptags'); |
|||
|
|||
const mongoose = require('mongoose'); |
|||
const Domain = mongoose.model('Domain'); |
|||
|
|||
const { SiteService, SiteError } = require('../../lib/site-lib'); |
|||
|
|||
class DomainService extends SiteService { |
|||
|
|||
constructor (dtp) { |
|||
super(dtp, module.exports); |
|||
} |
|||
|
|||
async create (domainDefinition) { |
|||
const NOW = new Date(); |
|||
const domain = new Domain(); |
|||
domain.created = NOW; |
|||
domain.name = striptags(domainDefinition.name.trim().toLowerCase()); |
|||
await domain.save(); |
|||
return domain.toObject(); |
|||
} |
|||
|
|||
async update (domain, domainDefinition) { |
|||
await Domain.updateOne( |
|||
{ _id: domain._id }, |
|||
{ |
|||
$set: { |
|||
name: striptags(domainDefinition.name.trim().toLowerCase()), |
|||
}, |
|||
}, |
|||
); |
|||
} |
|||
|
|||
async getSiteDomain ( ) { |
|||
return this.getByName(process.env.DTP_SITE_DOMAIN_KEY); |
|||
} |
|||
|
|||
async getById (domainId) { |
|||
const domain = await Domain.findById(domainId).lean(); |
|||
return domain; |
|||
} |
|||
|
|||
async getByName (domainName) { |
|||
const domain = await Domain.findOne({ name: domainName.toLowerCase().trim() }).lean(); |
|||
if (!domain) { |
|||
throw new SiteError(404, 'Domain does not exist'); |
|||
} |
|||
return domain; |
|||
} |
|||
|
|||
async getDomains (pagination) { |
|||
const domains = await Domain |
|||
.find() |
|||
.sort({ name: 1 }) |
|||
.skip(pagination.skip) |
|||
.limit(pagination.cpp) |
|||
.lean(); |
|||
return domains; |
|||
} |
|||
} |
|||
|
|||
module.exports = { |
|||
slug: 'domain', |
|||
name: 'domain', |
|||
create: (dtp) => { return new DomainService(dtp); }, |
|||
}; |
@ -1,26 +0,0 @@ |
|||
extends ../layouts/main |
|||
block content |
|||
|
|||
table.uk-table |
|||
thead |
|||
th Channel Name |
|||
th Domain |
|||
th Created |
|||
th Member |
|||
th Audience |
|||
th Status |
|||
tbody |
|||
each application in applications |
|||
tr |
|||
td |
|||
a(href=`/admin/channel-application/${application._id}`)= application.name |
|||
td= application.domain ? application.domain.name : 'N/A' |
|||
td= moment(application.created).fromNow() |
|||
td |
|||
a(href=`/admin/member/${application.owner._id}`)= application.owner.username |
|||
td= numeral(application.interview.audienceSize).format('0,0') |
|||
td(class={ |
|||
'uk-text-primary': ['new','review'].includes(application.status), |
|||
'uk-text-success': (application.status === 'approved'), |
|||
'uk-text-danger': (application.status === 'rejected'), |
|||
})= application.status |
@ -1,79 +0,0 @@ |
|||
extends ../layouts/main |
|||
block content |
|||
|
|||
.uk-card.uk-card-secondary.uk-card-body.uk-margin |
|||
fieldset.uk-fieldset |
|||
legend.sr-only Channel Information |
|||
div(uk-grid) |
|||
.uk-width-expand |
|||
.uk-margin |
|||
label.uk-form-label Channel Name: |
|||
.uk-text-large.uk-text-bold= application.name |
|||
.uk-width-auto |
|||
.uk-margin |
|||
label.uk-form-label Owner: |
|||
div |
|||
a(href=`mailto:${application.owner.email}?subject=${encodeURIComponent(site.name)}${encodeURIComponent(': ')}${encodeURIComponent(application.name)}`)= application.owner.displayName || application.owner.email |
|||
.uk-width-auto |
|||
.uk-margin |
|||
label.uk-form-label Phone: |
|||
div |
|||
a(href=`tel:${application.contact.phone.number}`)= application.contact.phone.number |
|||
.uk-width-auto |
|||
.uk-margin |
|||
label.uk-form-label Submitted: |
|||
div= moment(application.created).fromNow() |
|||
|
|||
.uk-margin |
|||
label.uk-form-label Description |
|||
div!= marked(application.description) |
|||
|
|||
div(uk-grid) |
|||
.uk-width-auto |
|||
.uk-margin |
|||
label.uk-form-label Category |
|||
div= application.category.name |
|||
.uk-width-auto |
|||
.uk-margin |
|||
label.uk-form-label Short Name |
|||
div= application.slug |
|||
.uk-width-auto |
|||
.uk-margin |
|||
label.uk-form-label Search Tags |
|||
div= application.tags ? application.tags.join(',') : 'N/A' |
|||
|
|||
.uk-card.uk-card-secondary.uk-card-body.uk-margin |
|||
fieldset.uk-fieldset |
|||
legend.uk-legend Interview |
|||
|
|||
div(uk-grid) |
|||
div(class="uk-width-1-1 uk-width-auto@m") |
|||
.uk-margin |
|||
label.uk-form-label Audience Size |
|||
div= application.interview.audienceSize |
|||
div(class="uk-width-1-1 uk-width-auto@m") |
|||
.uk-margin |
|||
label.uk-form-label Demo URL |
|||
div |
|||
a(href= application.interview.demoUrl)= application.interview.demoUrl |
|||
|
|||
.uk-margin |
|||
label.uk-form-label History |
|||
div!= marked(application.interview.history) |
|||
|
|||
.uk-card.uk-card-secondary.uk-card-body.uk-margin |
|||
form(method="POST", action=`/admin/channel-application/${application._id}`).uk-form |
|||
.uk-margin |
|||
label(for="rejected-reason").uk-form-label Rejection explanation |
|||
textarea(id="rejected-reason", name="rejectedReason", rows="4", placeholder= "Enter reason for rejecting").uk-textarea |
|||
div(uk-grid) |
|||
.uk-width-auto |
|||
button(type="submit", name="action", value="approve").uk-button.uk-button-primary |
|||
span |
|||
i.fas.fa-check |
|||
span.uk-text-bold.uk-margin-small-left Approve |
|||
.uk-width-auto |
|||
button(type="submit", name="action", value="reject").uk-button.uk-button-danger |
|||
span |
|||
i.fas.fa-times |
|||
span.uk-text-bold.uk-margin-small-left Reject |
@ -1,28 +0,0 @@ |
|||
extends ../layouts/main |
|||
block content |
|||
|
|||
.uk-overflow-auto |
|||
table.uk-table.uk-table-small.uk-table-divider |
|||
thead |
|||
th Channel |
|||
th Owner |
|||
th Category |
|||
th Status |
|||
th Created |
|||
tbody |
|||
each channel in channels |
|||
tr |
|||
td |
|||
a(href=`/admin/channel/${channel._id}`)= channel.name |
|||
|
|||
td |
|||
a(href=`/admin/user/${channel.owner._id}`)= channel.owner.username |
|||
|
|||
td= channel.category.name |
|||
|
|||
td(class={ |
|||
'uk-text-success': (channel.status === 'live'), |
|||
'uk-text-default': (channel.status === 'offline'), |
|||
})= channel.status |
|||
|
|||
td= moment(channel.created).format('MMM DD, YYYY') |
@ -1,13 +0,0 @@ |
|||
extends ../layouts/main |
|||
block content |
|||
|
|||
- var formAction = domain ? `/admin/domain/${domain._id}` : "/admin/domain"; |
|||
|
|||
h2 Domain Manager |
|||
|
|||
form(method="POST", action= formAction).uk-form |
|||
.uk-margin |
|||
label(for="name").uk-form-label Name |
|||
input(id="name", name="name", type="text", placeholder= "Enter domain name", value= domain ? domain.name : undefined).uk-input |
|||
.uk-margin |
|||
button(type="submit").uk-button.uk-button-primary= domain ? 'Update domain' : 'Create domain' |
@ -1,18 +0,0 @@ |
|||
extends ../layouts/main |
|||
block content |
|||
|
|||
.uk-margin |
|||
div(uk-grid).uk-flex-middle |
|||
.uk-width-expand |
|||
h2 Domain Manager |
|||
.uk-width-auto |
|||
a(href="/admin/domain/create").uk-button.uk-button-primary |
|||
span |
|||
i.fas.fa-plus |
|||
span.uk-margin-small-left Add domain |
|||
|
|||
.uk-margin |
|||
uk.uk-list |
|||
each domain in domains |
|||
li |
|||
a(href=`/admin/domain/${domain._id}`)= domain.name |
@ -1,19 +1,19 @@ |
|||
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="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="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}`) |
|||
|
Before Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 670 B |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 99 KiB |
Before Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 232 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 795 B |
Before Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 103 KiB |
Before Width: | Height: | Size: 145 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 205 KiB |
Before Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 326 KiB |
Before Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 581 B After Width: | Height: | Size: 581 B |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 134 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 117 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 685 B |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 67 KiB |
Before Width: | Height: | Size: 1.9 KiB |