@ -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="57x57" href=`/img/icon/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="60x60" href=`/img/icon/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="72x72" href=`/img/icon/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="76x76" href=`/img/icon/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="114x114" href=`/img/icon/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="120x120" href=`/img/icon/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="144x144" href=`/img/icon/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="152x152" href=`/img/icon/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="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/${site.domainKey}/icon-32x32.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/${site.domainKey}/icon-96x96.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/${site.domainKey}/icon-16x16.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/${site.domainKey}/icon-512x512.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/${site.domainKey}/icon-384x384.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/${site.domainKey}/icon-512x512.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/${site.domainKey}/icon-192x192.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}`) |
link(rel="manifest" href=`/manifest.json?v=${pkg.version}`) |
||||
meta(name="msapplication-TileColor" content="#f1c52f") |
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/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 |